Toda la verdad sobre RTOS. Artículo # 15. Particiones de memoria: servicios y estructuras de datos



En este artículo, continuamos revisando las secciones de memoria del RTOS.

Nucleus RTOS tiene tres llamadas API que proporcionan funciones de utilidad relacionadas con los grupos de particiones de almacenamiento: devolver información sobre grupos de particiones, devolver el número de grupos de particiones en una aplicación y devolver punteros a todos los grupos de particiones en una aplicación. Los dos primeros desafíos se implementan en Nucleus SE.

Artículos anteriores de la serie:
Artículo # 14. Secciones de memoria: introducción y servicios básicos.
Artículo 13. Estructuras de datos de tareas y llamadas de API no compatibles
Artículo # 12. Servicios para trabajar con tareas.
Artículo # 11. Tareas: configuración e introducción a la API
Artículo # 10. Programador: funciones avanzadas y preservación del contexto
Artículo # 9. Programador: implementación
Artículo # 8. Nucleus SE: diseño interno y despliegue
Artículo # 7. Núcleo SE: Introducción
Artículo # 6. Otros servicios RTOS
Artículo # 5. Interacción de tareas y sincronización
Artículo # 4. Tareas, cambio de contexto e interrupciones
Artículo # 3. Tareas y planificación
Artículo # 2. RTOS: estructura y modo en tiempo real
Artículo # 1. RTOS: introducción.

Recuperación de la información del grupo de particiones


Esta llamada de servicio proporciona información parcial sobre el grupo de particiones. La implementación de Nucleus SE difiere de Nucleus RTOS en que devuelve menos información porque no se admiten nombres de objetos y solicitudes de pausa, y la tarea no se puede detener.

Llamar a información de agrupación de particiones en Nucleus RTOS


Prototipo de llamada:

ESTADO NU_Partition_Pool_Information (NU_PARTITION_POOL * pool, CHAR * name, VOID ** start_address, UNSIGNED * pool_size, UNSIGNED * division_size, UNSIGNED * available, UNSIGNED * alloved, OPTION * suspend_type, UNSIGNED * tareas_waiting ** first__kiting_ first_kiting

Parámetros:

pool : un puntero al pool de particiones sobre el que se solicita información;
nombre : puntero al área de destino de 8 caracteres para el nombre del grupo de particiones; incluye un lugar para terminar cero;
start_address : un puntero a una variable que recibe un puntero al comienzo del área de datos del grupo de particiones;
pool_size : un puntero a una variable que recibe el tamaño del grupo de particiones (en bytes);
Partition_size : puntero a una variable que obtiene el tamaño de las particiones en un grupo determinado;
disponible : un puntero a una variable que recibe el número de particiones actualmente disponibles en este grupo;
asignado : un puntero a una variable que recibe el número de particiones utilizadas actualmente en un grupo dado;
suspend_type : puntero a una variable para obtener el tipo de suspensión de la tarea; tipos de suspensión válidos: NU_FIFO y NU_PRIORITY ;
task_waiting : un puntero a una variable que recibe el número de tareas suspendidas en un grupo de particiones dado;
first_task : puntero al puntero de la tarea en el que se encuentra el puntero de la primera tarea suspendida.

Valor de retorno:

NU_SUCCESS - llamada completada con éxito;
NU_INVALID_POOL : puntero no válido al grupo de particiones.

Llamando a la información del grupo de particiones en el núcleo SE


Prototipo de llamada:

ESTADO NUSE_Partition_Pool_Information (agrupación NUSE_PARTITION_POOL, ADDR * start_address, U32 * pool_size, U16 * division_size, U8 * disponible, U8 * asignado, U8 * task_waiting, NUSE_TASK * first_task)

Parámetros:

pool : el índice del pool de particiones sobre el que se solicita información;
start_address : un puntero a una variable que recibe un puntero al comienzo del área de datos del grupo de particiones;
pool_size : un puntero a una variable que recibe el tamaño del grupo de particiones (en bytes);
Partition_size : puntero a una variable que obtiene el tamaño de las particiones en un grupo determinado;
disponible : un puntero a una variable que recibe el número de particiones actualmente disponibles en este grupo;
asignado : un puntero a una variable que recibe el número de particiones utilizadas actualmente en un grupo dado;
task_waiting : un puntero a una variable que recibe el número de tareas suspendidas en este grupo de particiones (si la suspensión de tareas está desactivada, se devuelve 0);
first_task : un puntero a una variable de tipo NUSE_TASK , que recibe el índice de la primera tarea suspendida (si la suspensión de la tarea está desactivada, se devuelve 0).

Valor de retorno:

NUSE_SUCCESS - llamada completada con éxito;
NUSE_INVALID_POOL : índice de agrupación de particiones no válido;
NUSE_INVALID_POINTER : uno o más de los punteros pasados ​​no son válidos.

Implementación de recuperación de información y agrupación de particiones en Nucleus SE


Implementar una llamada API de este tipo es simple de ejecutar:



La función devuelve el estado del grupo de particiones. Luego, si se activa el bloqueo de llamadas API, se devuelve el número de tareas pendientes y el índice de la primera de ellas (de lo contrario, estos parámetros se establecen en 0).

Obtener el número de grupos de particiones


Esta llamada devuelve información sobre el número de agrupaciones de particiones configuradas en la aplicación. Mientras que en Nucleus RTOS este número cambia con el tiempo y el valor de retorno representará el número actual de agrupaciones, en Nucleus SE el valor de retorno se establece durante el ensamblaje y permanece sin cambios.

El desafío de obtener el número de grupos de particiones en Nucleus RTOS


La llamada admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada:

NU_SIGNED NU_Established_Partition_Pools (VOID);

Parámetros:

Están ausentes

Valor de retorno:

El número de agrupaciones de particiones creadas en la aplicación.

El desafío de obtener el número de grupos de particiones en Nucleus SE


Esta llamada de utilidad admite la funcionalidad principal de la API Nucleus RTOS.

Prototipo de llamada:

U8 NUSE_Partition_Pool_Count (nulo);

Parámetros:

Están ausentes

Valor de retorno:

El número de agrupaciones de particiones creadas en la aplicación.

Implementación


La implementación de esta llamada API es extremadamente simple: se devuelve el valor #define del símbolo NUSE_PARTITION_POOL_NUMBER .

Estructuras de datos


Al igual que todos los demás objetos de Nucleus SE, las agrupaciones de particiones usan matrices de estructura en ROM y RAM, cuyo número depende de la cantidad de agrupaciones especificadas en la configuración.

Recomiendo encarecidamente que el código de la aplicación acceda a dichas estructuras de datos a través de funciones API y no directamente. Esto evita la incompatibilidad con futuras versiones de Nucleus SE y los efectos secundarios no deseados, y también simplifica la transferencia de la aplicación a Nucleus RTOS. La siguiente es una descripción detallada de las estructuras de datos para facilitar la comprensión del código de llamada de servicio y la depuración.

Estructura de los datos del kernel colocados en la RAM


Estas estructuras de datos incluyen:

NUSE_Partition_Pool_Partition_Used [] : una matriz de tipo U8 , que tiene una entrada para cada grupo de particiones configurado, que contiene un contador de los grupos utilizados actualmente;
NUSE_Partition_Pool_Blocking_Count [] : una matriz de tipo U8 que contiene un contador de tareas bloqueadas en cada grupo de particiones. Esta matriz existe si es posible bloquear la llamada a la API.

Dichas estructuras de datos se inicializan en ceros utilizando NUSE_Init_ Partition_Pool () al iniciar Nucleus SE. Esto es lógico porque hace que cada partición en cada grupo no se use (gratis). El siguiente artículo proporcionará una descripción completa de los procedimientos de inicio en Nucleus SE.

Las siguientes son descripciones de las estructuras de datos en el archivo nuse_init.c .



Datos de usuario RAM


El usuario debe asignar un área en RAM para almacenar datos para cada grupo de particiones. La cantidad de espacio en RAM debe corresponder al volumen de particiones configuradas (consulte "Datos en ROM" a continuación) con un byte adicional para cada partición en el grupo. Cada sección del área de datos está precedida por un byte de estado.

Datos ROM


Estos incluyen:

NUSE_Partition_Pool_Data_Address [] : una matriz de tipo ADDR , con una entrada para cada grupo de particiones configurado, que contiene la dirección del comienzo del área de almacenamiento de datos;
NUSE_Partition_Pool_Partition_Number [] : una matriz de tipo U8 con una entrada para cada grupo de particiones configurado, que contiene información sobre el número de particiones en el grupo;
NUSE_Partition_Pool_Partition_Size [] : una matriz de tipo U16 con una entrada para cada grupo de particiones configurado, que contiene el tamaño de las particiones para los grupos.

Dichas estructuras de datos se declaran e inicializan (estáticamente) en nuse_config.c :



Huella de datos para el grupo de particiones


Al igual que con todos los objetos principales en Nucleus SE, la cantidad de memoria requerida para los grupos de particiones es predecible.

El tamaño de ROM (en bytes) para todos los grupos de particiones de aplicaciones se puede calcular de la siguiente manera:

NUSE_PARTITION_POOL_NUMBER * (tamaño de (ADDR) + 2)

La cantidad de datos del kernel en RAM para todos los grupos de particiones de aplicaciones cuando se activa el bloqueo de llamadas API toma solo 2 bytes por grupo de particiones, y cuando el bloqueo no se activa, toma 1 byte.

La cantidad de memoria para almacenar datos de usuario en RAM varía para cada grupo de particiones, aunque, como ya se mencionó, para un grupo con índice n se puede calcular como:

NUSE_Partition_Pool_Partition_Number [n] *
(NUSE_Partition_Pool_Partition_Size [n] + 1)

Llamadas API no realizadas


Tres llamadas API para agrupaciones de particiones implementadas en Nucleus RTOS no son compatibles con Nucleus SE.

Crear grupo de particiones


Esta llamada a la API crea un grupo de particiones. Nucleus SE no lo necesita porque las tareas se crean de forma estática.

Prototipo de llamada:

ESTADO NU_Create_Partition_Pool (NU_PARTITION_POOL * pool, CHAR * name, VOID * start_address, UNSIGNED pool_size, UNSIGNED division_size, OPTION suspend_type);

Parámetros:

pool : un puntero a una unidad de control de pool de partición definida por el usuario; se usa como identificador para el grupo de particiones en otras llamadas API;
nombre : un puntero al nombre del grupo de particiones, una cadena de 7 caracteres con un cero final;
start_address : establece la dirección de inicio para el área de memoria del grupo de particiones;
pool_size : cantidad total de memoria en bytes;
Partition_size : la cantidad de memoria en bytes para cada partición en el grupo. Además de esto, se asigna una pequeña cantidad adicional de memoria asociada a cada sección, que se realiza gracias a los dos punteros de datos utilizados.
suspend_type : determina cómo se suspenden las tareas en el grupo de particiones; Las opciones de parámetro válidas son NU_FIFO y NU_PRIORITY .

Valor de retorno:

NU_SUCCESS - indica una finalización exitosa de la llamada;
NU_INVALID_POOL : indica el valor cero de la unidad de control de agrupación de particiones ( NULL );
NU_INVALID_MEMORY : indica el valor cero del área de memoria definida por start_ address ( NULL );
NU_INVALID_SIZE : indica que el tamaño de la partición es 0 o mayor que la memoria asignada para la partición;
NU_INVALID_SUSPEND : valor de tipo suspendido no válido .

Eliminar grupo de particiones


Esta llamada a la API elimina un grupo de particiones creado previamente. Nucleus SE no lo necesita porque los objetos se crean de forma estática y no se pueden eliminar.

Prototipo de llamada:

ESTADO NU_Delete_Partition_Pool (NU_PARTITION_POOL * pool);

Parámetros:

pool - puntero a la unidad de control de pool de partición;

Valor de retorno:

NU_SUCCESS - indica una finalización exitosa de la llamada;
NU_INVALID_POOL : indica un valor no válido para el puntero del grupo de particiones;

Partition Pool Pointers


Esta llamada a la API crea una lista secuencial de punteros a todos los grupos de particiones del sistema. Nucleus SE no necesita esto porque los objetos se identifican mediante un índice, no un puntero.

Prototipo de llamada:

UNSIGNED NU_Partition_Pool_Pointers (NU_PARTITION_POOL ** pointer_list, UNSIGNED maximum_pointers);

Parámetros:

pointer_list : puntero a una matriz de punteros NU_PARTITION_POOL ; la matriz está llena de punteros a grupos configurados en el sistema;
maximum_pointers : el número máximo de punteros que se pueden colocar en la matriz.

Valor de retorno:

El número de punteros NU_PARTITION_POOL colocados en la matriz.

Nucleus RTOS Compatible


Al desarrollar Nucleus SE, una de las tareas principales era garantizar un alto nivel de compatibilidad de código con Nucleus RTOS. Los grupos de particiones no fueron una excepción y, desde el punto de vista del desarrollador, se implementan de la misma manera que en Nucleus RTOS. Algunas áreas existentes de incompatibilidad son aceptables, aunque vale la pena considerar que el código final es más fácil de entender y más eficiente en términos de memoria. Sin embargo, las llamadas a la API Nucleus RTOS se pueden usar casi directamente como llamadas a Nucleus SE. Se planea un artículo futuro con información sobre el uso de Nucleus SE por parte de los usuarios de Nucleus RTOS.

Identificadores de objetos


En Nucleus RTOS, todos los objetos se describen mediante estructuras de datos (unidades de control) de un tipo específico. Se utiliza un puntero a este bloque de control como identificador para el grupo de particiones. Decidí que Nucleus SE requería un enfoque diferente para un uso más eficiente de la memoria. Todos los objetos del núcleo están descritos por varias tablas en RAM y / o ROM. Los tamaños de estas tablas están determinados por el número de tipos configurables de todos los objetos. El identificador para un objeto particular es el índice en estas tablas. Por lo tanto, determiné que NUSE_PARTITION_POOL es equivalente a U8 , después de lo cual una variable (no un puntero) de este tipo sirve como identificador de la tarea. Esta ligera incompatibilidad es fácil de descubrir si el código se transfiere desde o hacia Nucleus RTOS. Los identificadores de objetos generalmente se almacenan y transmiten sin cambios.

Nucleus RTOS también admite el nombre de agrupaciones de particiones. Estos nombres se usan solo para la depuración. Los excluí de Nucleus SE para ahorrar memoria.

Número de secciones y su volumen.


En Nucleus RTOS, el grupo de particiones se configura en función del volumen total del grupo y el volumen de particiones (que llevan 2 punteros más). Estos parámetros se definen como SIN FIRMAR (aproximadamente 32 bits). En Nucleus SE, el grupo de particiones se configura en función del tamaño de la partición (para lo cual se ha agregado un byte adicional) y el número total de particiones. Estos parámetros se definen como U16 y U8, respectivamente.

Llamadas API no realizadas


Nucleus RTOS admite 7 llamadas para trabajar con grupos de particiones, 3 de las cuales no están implementadas en Nucleus SE. Más arriba se detallan más detalles sobre estos desafíos y los motivos de su exclusión.

El próximo artículo será sobre señales.

Sobre el autor: Colin Walls ha trabajado en la industria electrónica durante más de treinta años, dedicando la mayor parte de su tiempo al firmware. Ahora es ingeniero de firmware en Mentor Embedded (una división de Mentor Graphics). Colin Walls a menudo habla en conferencias y seminarios, autor de numerosos artículos técnicos y dos libros sobre firmware. Vive en el Reino Unido. Blog profesional de Colin , correo electrónico: colin_walls@mentor.com.

Source: https://habr.com/ru/post/es426477/


All Articles