Implementuju si pro větší projekt modul na práci se sériovou linkou, který poskytuje funkce jako getchar a putchar apod pracující s vlastními kruhovými buffery. Vycházel jsem z dokumentace k STM32 HAL API (která je pěkně na hovno někdy) a examplů z STM32CubeF0 (www2.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software/stm32cubef0.html)
Zkoušel jsem několik kombinací nastavení DMA UARTu(normal nebo circular mode) nebo přes klasické přerušení RX/TX.
Nejspolehlivěji funguje DMA v kruhovým módu…ostatní nějak blbnou (viz dále) a netuším jestli to je vlastnost těch periferií nebo mám prostě něco shnilého v kódu.
Používám nejnovější ST CubeMX pro generování výchozího kódu a nastavení periferií pro toolchain SW4STM32. Kód pak dopisuju a ladím v Embitzu (nástupce Emblocks, projektový soubor se dá z cubemx přepsat ručně nebo vygenerovat utilitou cube2block arts-union.ru/node/32 ). Zdrojáky (i s examply z STM32CubeF) s projektem pro embitz (emblocks) jsou v příloze.
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
serial_init();
uint8_t c;
char Txbufferlong]="123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789KONEC\n";
char Txbuffershort]="123456789\n";
while (1)
{
//bez ukoncovaciho znaku \0 retezce
serial_transmit((uint8_t*)Txbufferlong, sizeof(Txbufferlong)/sizeof(Txbufferlong[0]) - 1);
serial_transmit((uint8_t*)Txbuffershort, sizeof(Txbuffershort)/sizeof(Txbuffershort[0]) - 1);
while(serial_getByte(&c))
{
serial_transmit(&c,1);
//HAL_Delay(10);
}
}
}
Pokud mám UART RX DMA v kruhovém módu, tak tenhle kód funguje bez problému. V hlavní smyčce dokola posílá dlouhou a krátkou zprávu a mezitím kontroluje pomocí uživatelské funkce int serial_getByte(uint8_t*) jestli v přijímacím kruhovým bufferu jsou nějaký bajty. Zkoušel jsem RX zahlcovat všelijakými blbostma (od krátkých 10B zpráv po 128 B těsně za sebou) a bez problému. Vše kontrolováno logickým analyzýtorem a jednoduše v terminálu na PC.
Pokud ale DMA pro RX nastavím do normal módu, tak mi přeposílání přijatých znaků zpět po čase zamrzne. Hlavní smyčka jede dál (stále odesílám krátké a dlouhé řetězce), ale přijímací část je nějak mrtvá. Zkoušel jsem to debugovat plus používat semihosting na posílání testovacích zpráv a nic jsem nezjistil. Zachytil jsem, že po přijmutí znaků obdobně jako při správcné funkci (DMA circular mode) program skáče do handlerů v tom API.
Zjistil jsem, že pokud přijme krátké zprávy s nějakou prodlevou nebo přidám řádek s HAL_Delay(10) za vysílání, tak to nějak žije - zase zamrzne, pokud přijme několik dlouhých zpráv za sebou…
Když vypnu DMAčko a nechám klasické přerušení (v modulu serial.c je třeba místo API funkcí HAL_UART_Receive/Transmit_DMA používat HAL_UART_Receive/Transmit_IT), tak program opět funguje, ale jenom pokud je odkomentován řádek se zpožděním.
Zkrátka je sice fajn, že mi to zřejmě bez problému pojede pro RX DMAčko v kruhovým módu, ale vadí mi, že pro klasické přerušení se to chová takhle divně. Už nad tím hniju několik hodin a jsem zkrátka v koncích .
uart_test.zip (1.14 MB)