STM32: reinicie el puntero de dirección DMA I2S

1

Para mi aplicación tengo un DAC que se comunica con un STM32F4 a través de I2S. En el lado del microcontrolador, las informaciones se envían al DAC a través de un flujo DMA, con un búfer circular. En una interrupción externa, me gustaría pausar el DMA, cambiar algunos parámetros de sonido y luego reanudar la secuencia DMA.

Mi rutina de interrupción es básicamente así:

void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
    if(pin == GPIO_PIN_13)
    {
        HAL_I2S_DMAPause(&hi2s2);
        changeSound(&sound);
        HAL_I2S_DMAResume(&hi2s2);
    }
}

Y tengo 2 rutinas de interrupción activadas en DMA TxHalf / TxCplt que llenan cada mitad de mi búfer DMA con el sonido. ( EDIT : durante mi investigación también aprendí que hay un "modo de doble búfer" que permite hacer eso con algunas ventajas, pero eso está fuera de tema).

Lo que quiero evitar es transferir algunas muestras restantes del sonido anterior después de mi interrupción Exti. Así que mi idea fue llenar todo el búfer después de cambiar el sonido y luego restablecer el puntero de memoria de la secuencia DMA al principio de mi búfer.

Se vería algo así:

void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
    if(pin == GPIO_PIN_13)
    {
        HAL_I2S_DMAPause(&hi2s2);
        changeSound(&sound);
        fillBuffer( address_of_1st_half, &sound);
        fillBuffer( address_of_2nd_half, &sound);
        *reset_DMA(&hi2s2)*; <==== this is the function I'm looking for
        HAL_I2S_DMAResume(&hi2s2);
    }
}

nb: como puede ver, estoy usando los controladores HAL de CubeMX

He consultado la hoja de datos de HAL para esta función, pero no he encontrado ninguna.

Lo único que está cerca de eso es usar DMAStop () y luego Transmit_DMA () nuevamente. Pero me temo que eso llevaría demasiado tiempo ...

Si alguien tiene una idea, me encantaría escucharla.

Gracias

    
pregunta Florent

1 respuesta

1

Bien, es posible que no haya encontrado una manera de restablecer realmente el puntero DMA sin deshabilitar la transmisión (todavía), pero encontré más información y una manera de evitar el problema.

  • Cuando usa el modo circular con el incremento del puntero, la dirección de los datos a transferir se calcula a partir del registro DMA_SxNDTR (que contiene el número restante de datos que se enviarán) y el registro DMA_SxM0AR (que contiene la dirección ASE para el Secuencia de DMA). El puntero es la dirección base compensada por el tamaño del búfer menos el valor DMA_SxNDTR. Si restablece DMA_SxNDTR al tamaño de los datos, restablece el puntero a la dirección base (por lo que pude entender, podría estar equivocado). Sin embargo, no puede cambiar el valor del registro a menos que la secuencia esté deshabilitada. Entonces, para restablecer el puntero, tendría que deshabilitar la transmisión, restablecer DMA_SxNDTR y luego reactivar la transmisión.
  • Sin embargo, puede leer el registro DMA_SxNDTR para saber en qué parte del búfer se encuentra, de modo que solo pueda rellenar la otra mitad. En ese caso, el periférico recibiría los restos del sonido anterior y luego comenzará a leer el nuevo sonido de forma segura.
  • Una tercera posibilidad sería leer el DMA_SxNDTR y comenzar a rellenar el búfer solo cuando no haya más datos para transferir. Se agrega en latencia pero evita que el sonido antiguo aún se reproduzca.

La última solución se vería así:

void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
    if(pin == GPIO_PIN_13)
    {
        changeSound(&sound);
        while(DMA1_Stream4->NDTR >= 1);
        HAL_I2S_DMAPause(&hi2s2);
        fillBuf(&buf, &sound);
        HAL_I2S_DMAResume(&hi2s2);
    }
}

No lo he probado todavía, así que no puedo estar seguro de si funciona o no, actualizaré esta respuesta tan pronto como lo haga.

Fuentes:

respondido por el Florent

Lea otras preguntas en las etiquetas