cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA cannot send multiply bytes

AlanCui4080
Associate II

Hi,

 

I'm using STM32G431 to drive my SPI screen. Due to the high cpu load, i decided to change the IT sending mode to DMA. After putting a little changes on code, it doesn't work any more, and i have confirmed it will work again once get it back to IT mode.

I placed breakpoints in HAL_SPI_ErrorCallback and HAL_SPI_Transmit_DMA, besides my oscilloscope probes on MOSI and SCK. It seems that it would success if i send only one byte per request, and fail if i send 0x80 bytes.

I checked SPI_SR, bit BSY and TXE was set when HAL_SPI_ErrorCallback was called. And one more confused thing is it failed at the third tires, even through the first and second tries was not send.

 

 

// void SPI2_IRQHandler(void) // { // HAL_SPI_IRQHandler(&screen_spi_handle); // } void DMA1_Channel1_IRQHandler(void) { HAL_DMA_IRQHandler(&screen_dma_handle); } void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) { (void)hspi; vTaskNotifyGiveFromISR(screen_task_handle, NULL); } void HAL_SPI_ErrorCallback(SPI_HandleTypeDef* hspi) { while (1) { } }

 

screen.c:

 

void screen_init() { gpio_screen_mosi.Pin = GPIO_PIN_15; gpio_screen_mosi.Mode = GPIO_MODE_AF_PP; gpio_screen_mosi.Pull = GPIO_NOPULL; gpio_screen_mosi.Speed = GPIO_SPEED_FREQ_MEDIUM; gpio_screen_mosi.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &gpio_screen_mosi); gpio_screen_sck.Pin = GPIO_PIN_13; gpio_screen_sck.Mode = GPIO_MODE_AF_PP; gpio_screen_sck.Pull = GPIO_NOPULL; gpio_screen_sck.Speed = GPIO_SPEED_FREQ_MEDIUM; gpio_screen_sck.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &gpio_screen_sck); gpio_screen_cs.Pin = GPIO_PIN_12; gpio_screen_cs.Mode = GPIO_MODE_OUTPUT_PP; gpio_screen_cs.Pull = GPIO_PULLUP; gpio_screen_cs.Speed = GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOB, &gpio_screen_cs); gpio_screen_dc.Pin = GPIO_PIN_11; gpio_screen_dc.Mode = GPIO_MODE_OUTPUT_PP; gpio_screen_dc.Pull = GPIO_NOPULL; gpio_screen_dc.Speed = GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOB, &gpio_screen_dc); gpio_screen_reset.Pin = GPIO_PIN_10; gpio_screen_reset.Mode = GPIO_MODE_OUTPUT_PP; gpio_screen_reset.Pull = GPIO_PULLDOWN; gpio_screen_reset.Speed = GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOB, &gpio_screen_reset); __HAL_RCC_SPI2_CLK_ENABLE(); screen_spi_handle.Instance = SPI2; screen_spi_handle.Init.Mode = SPI_MODE_MASTER; screen_spi_handle.Init.Direction = SPI_DIRECTION_2LINES; screen_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT; screen_spi_handle.Init.CLKPolarity = SPI_POLARITY_HIGH; screen_spi_handle.Init.CLKPhase = SPI_PHASE_2EDGE; screen_spi_handle.Init.NSS = SPI_NSS_SOFT; screen_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; // 2.25Mhz screen_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB; screen_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE; screen_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; screen_spi_handle.Init.CRCPolynomial = 7; screen_spi_handle.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE; screen_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; HAL_StatusTypeDef result = HAL_SPI_Init(&screen_spi_handle); if (result != HAL_OK) hal_perror("screen", "HAL_SPI_Init", result); // HAL_NVIC_SetPriority(SPI2_IRQn, 2, 0); // HAL_NVIC_EnableIRQ(SPI2_IRQn); __HAL_RCC_DMAMUX1_CLK_ENABLE(); __HAL_RCC_DMA1_CLK_ENABLE(); screen_dma_handle.Instance = DMA1_Channel1; screen_dma_handle.Init.Request = DMA_REQUEST_SPI2_TX; screen_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE; screen_dma_handle.Init.MemInc = DMA_MINC_ENABLE; screen_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; screen_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; screen_dma_handle.Init.Mode = DMA_NORMAL; screen_dma_handle.Init.Priority = DMA_PRIORITY_LOW; result = HAL_DMA_Init(&screen_dma_handle); if (result != HAL_OK) hal_perror("screen", "HAL_DMA_Init", result); __HAL_LINKDMA(&screen_spi_handle, hdmatx, screen_dma_handle); HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 2, 1); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); printf("screen: ready\n"); u8g2_Setup_sh1106_128x64_noname_f(&u8g2_handle, U8G2_R0, u8x8_byte_method, u8x8_gpio_and_delay_method); uint8_t* buf = (uint8_t*)pvPortMalloc(u8g2_GetBufferSize(&u8g2_handle)); // dynamically allocate a buffer of the // required size if (buf == NULL) hal_perror("screen", "pvPortMalloc", buf); u8g2_SetBufferPtr(&u8g2_handle, buf); u8g2_InitDisplay(&u8g2_handle); printf("screen: setup for sh1106_128x64_noname_f\n"); u8g2_SetPowerSave(&u8g2_handle, 0); u8g2_ClearBuffer(&u8g2_handle); u8g2_SetFont(&u8g2_handle, u8g2_font_profont12_mf); u8g2_DrawStr(&u8g2_handle, 0, 12, "Initializing..."); u8g2_SendBuffer(&u8g2_handle); printf("screen: \"Initializing...\" has been printed on the screen\n"); } uint8_t u8x8_byte_method(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { HAL_StatusTypeDef result; switch (msg) { case U8X8_MSG_BYTE_SEND: result = HAL_SPI_Transmit_DMA(&screen_spi_handle, (uint8_t*)arg_ptr, arg_int); if (result != HAL_OK) hal_perror("screen", "HAL_SPI_Transmit_DMA", result); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ...
View more

 

 

 

 

2 REPLIES 2
TDK
Guru

If HAL_SPI_ErrorCallback is called, the reason for the error will be found in the handle, in hspi->ErrorCode. It could be that the buffer is not in a location that the DMA can access.

Since DMA takes time to complete, you should also verify that the SPI is ready before you issue another DMA command.

If you feel a post has answered your question, please click "Accept as Solution".

Hi,

The hspi->ErrorCode =  0x20, which told /*!< Error on RXNE/TXE/BSY/FTLVL/FRLVL Flag */. Then, SPI_SR = 0x82, so BSY and TXE was set.

I'm using FreeRTOS so, the thread will block untill TxCpltCallback send signal to it.