Estoy familiarizado con varios kernels en tiempo real: AVIX , FreeRTOS , TNKernel , y en todos tenemos 2 versiones de casi todas las funciones: una para llamar desde la tarea y la segunda para llamar desde ISR.
Por supuesto, tiene sentido para las funciones que podrían cambiar de contexto y / o dormir: obviamente, ISR no puede dormir, y el cambio de contexto se debe hacer de manera diferente. Pero hay varias funciones que no cambian de contexto ni de suspensión: digamos, puede devolver el conteo de tics del sistema, o configurar el temporizador del software, etc.
Ahora, estoy implementando mi propio kernel: TNeoKernel , que tiene un código bien formado y se ha probado cuidadosamente, y Estoy considerando inventar funciones "universales" a veces: las que se pueden llamar desde cualquier tarea o contexto ISR. Pero como los tres núcleos mencionados utilizan funciones separadas, me temo que voy a hacer algo mal.
Por ejemplo, en el contexto de tareas e ISR, TNKernel usa diferentes rutinas para deshabilitar / restaurar interrupciones, pero por lo que veo, la única diferencia posible es que las funciones de ISR pueden "compilarse" como una optimización si la plataforma de destino no lo hace. No soporta interrupciones anidadas. Pero si la plataforma de destino admite interrupciones anidadas, la desactivación / restauración de las interrupciones parece absolutamente lo mismo para la tarea y el contexto ISR.
Por lo tanto, mi pregunta es : ¿existen plataformas en las que las interrupciones de deshabilitación / restauración de ISR se deben hacer de manera diferente a las del contexto que no es ISR?
Si no hay tales plataformas, preferiría ir con funciones "universales". Si tiene comentarios sobre este enfoque, son muy apreciados.
UPD: no me gusta tener dos conjuntos de funciones porque conducen a una duplicación y complicación notables del código. Por ejemplo, necesito proporcionar una función que debería iniciar el temporizador del software. Aquí está lo que parece:
enum TN_RCode _tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout)
{
/* ... real job is done here ... */
}
/*
* Function to be called from task
*/
enum TN_RCode tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout)
{
TN_INTSAVE_DATA; //-- define the variable to store interrupt status,
// it is used by TN_INT_DIS_SAVE()
// and TN_INT_RESTORE()
enum TN_RCode rc = TN_RC_OK;
//-- check that function is called from right context
if (!tn_is_task_context()){
rc = TN_RC_WCONTEXT;
goto out;
}
//-- disable interrupts
TN_INT_DIS_SAVE();
//-- perform real job, after all
rc = _tn_timer_start(timer, timeout);
//-- restore interrupts state
TN_INT_RESTORE();
out:
return rc;
}
/*
* Function to be called from ISR
*/
enum TN_RCode tn_timer_istart(struct TN_Timer *timer, TN_Timeout timeout)
{
TN_INTSAVE_DATA_INT; //-- define the variable to store interrupt status,
// it is used by TN_INT_DIS_SAVE()
// and TN_INT_RESTORE()
enum TN_RCode rc = TN_RC_OK;
//-- check that function is called from right context
if (!tn_is_isr_context()){
rc = TN_RC_WCONTEXT;
goto out;
}
//-- disable interrupts
TN_INT_IDIS_SAVE();
//-- perform real job, after all
rc = _tn_timer_start(timer, timeout);
//-- restore interrupts state
TN_INT_IRESTORE();
out:
return rc;
}
Por lo tanto, necesitamos envoltorios como los de arriba para casi todas las funciones del sistema. Este es un tipo de inconveniente, tanto para mí como desarrollador del kernel como para los usuarios del kernel.
La única diferencia es que se utilizan macros diferentes: para la tarea, estas son TN_INTSAVE_DATA
, TN_INT_DIS_SAVE()
, TN_INT_RESTORE()
; para las interrupciones, estos son TN_INTSAVE_DATA_INT
, TN_INT_IDIS_SAVE()
, TN_INT_IRESTORE()
.
Para las plataformas que admiten interrupciones anidadas (ARM, PIC32), estas macros son idénticas. Para otras plataformas que no admiten interrupciones anidadas, TN_INTSAVE_DATA_INT
, TN_INT_IDIS_SAVE()
y TN_INT_IRESTORE()
se expanden a nada. Por lo tanto, es un poco de optimización de rendimiento, pero el costo es demasiado alto en mi opinión: es más difícil de mantener, no es tan cómodo de usar y el tamaño del código aumenta.