Estoy trabajando en un MC STM32F401 para la adquisición de audio y estoy tratando de enviar los datos de audio (384 bytes exactamente) desde ISR a una tarea usando colas. La frecuencia del ISR es demasiado alta y, por lo tanto, creo que algunos datos se pierden debido a que la cola está llena. El audio grabado al ejecutar el código es ruidoso. ¿Hay alguna forma más sencilla de enviar grandes cantidades de datos desde un ISR a una tarea?
El RTOS utilizado es FreeRTOS y el ISR es la devolución de llamada DMA del periférico de micrófono I2S.
El enfoque general en estos casos es:
Puede implementar una cola de "copia cero" creando una cola de punteros a bloques de memoria en lugar de copiar la memoria en sí. Haga que los datos de audio se escriban directamente en un bloque (mediante DMA, por ejemplo), luego, cuando estén llenos, coloque un puntero en la cola del bloque y cambie al siguiente bloque disponible en el grupo. La tarea de recepción puede entonces operar directamente en el bloque de memoria sin necesidad de copiar los datos dentro y fuera de la cola; lo único que se copia es el puntero.
La tarea de recepción, cuando finaliza, devuelve el bloque al grupo. El grupo debe tener el mismo número de bloques que la longitud de la cola.
Para crear un grupo de memoria, comenzaría con una matriz estática:
tAudioSample block[QUEUE_LENGTH][BLOCK_SIZE] ; Luego llene una cola block_pool con punteros a cada elemento de bloque - pseudocódigo:
for( int i = 0; i < QUEUE_LENGTH; i++ ) { queue_send( block_pool, block[i] ) ; } Luego, para obtener un bloque "disponible", simplemente toma un puntero de la cola, lo llena y luego lo envía a su cola de transmisión de audio, y el receptor, cuando termina con el bloque, envía el puntero de vuelta a block_pool .
Algunos RTOS proporcionan un asignador de bloques fijo que hace exactamente lo que describí anteriormente con la cola block_pool . Si usa la API RTOS de CMSIS en lugar de la API nativa de FreeRTOS, eso proporciona una API de grupo de memoria .
Sin embargo, parece que esto puede ser un problema XY: presentó su diagnóstico, que puede ser correcto o no, y decidió una solución con la que luego está pidiendo ayuda. Pero, ¿y si es la solución incorrecta o no la óptima? Es mejor incluir algún código que muestre cómo se generan y consumen los datos, y proporcionar información concreta, como de dónde provienen estos datos, con qué frecuencia se genera el ISR, frecuencias de muestreo, la plataforma en la que se ejecuta, la prioridad y la programación del recibir la tarea y qué otras tareas se están ejecutando que podrían retrasarla.
En la mayoría de las plataformas, 384 bytes no es una gran cantidad de datos, y la tasa de interrupción tendría que ser extraordinariamente alta o la tarea de recepción tendría que retrasarse excesivamente (es decir, no en tiempo real) o realizar un trabajo excesivo o no determinista para causar este problema. Puede que el problema no sea la frecuencia de ISR, sino el rendimiento y la capacidad de programación de la tarea de recepción.
¿No está claro si los 384 bytes dan como resultado una sola interrupción o 384 interrupciones o qué?
Es decir, puede ser un problema de diseño más holístico en lugar de simplemente cómo pasar datos de manera más eficiente, aunque eso no puede ser algo malo.
Si el subproceso que recibe los datos se llama a intervalos periódicos, la cola debe tener el tamaño suficiente para contener todos los datos que se pueden recibir en ese intervalo. Probablemente sería una buena idea asegurarse de que la cola sea lo suficientemente grande como para contener datos durante al menos dos intervalos.
Si el subproceso que recibe los datos simplemente no puede mantenerse al día con los datos entrantes, entonces se podría considerar aumentar su prioridad.
Hay un procesamiento general asociado con cada inserción y extracción de la cola, ya que FreeRTOS verificará para determinar si una tarea de mayor prioridad debe activarse en respuesta a la acción. Al escribir o leer varios elementos hacia o desde la cola al mismo tiempo, puede ser útil suspender el programador mientras se realiza la transferencia.
Otra solución sería implementar un búfer circular y colocarlo en la memoria compartida. Esto básicamente realizará la misma función que una cola, pero sin la sobrecarga adicional. Es posible que deba usar un mutex para bloquear el acceso simultáneo al búfer, según cómo se implemente el búfer circular.