U5 DMA not setting interrupt or executing callback, stays busy
Using the latest CubeMXIDE, CubeIDE, and drivers.
Custom hardware driving an ILI9341 through SPI1
Driver (attached) writes column and page registers, writes RAMWRITE command, and then transfers in one of three methods: blocking, IRQ, and DMA.
blocking works fine, so the hardware and commands are proper.
IRQ and DMA do not work. Working specifically on DMA at the moment.
Software for the driver next:
case ROTATE_180:
{
// checked valid
// new design driver, landscape mode, draws left to right
// note: DISPLAY IS IN native landscape MODE
// range is 0-319 and 0-239
// reverse X if not commented out
// data.x0 = 319-data.x0;
// data.x1 = 319-data.x1;
// reverse Y if not commented out
// data.y0 = 239-data.y0;
// data.y1 = 239-data.y1;
minmax (data.x0, 0, 319);
minmax (data.x1, 0, 319);
minmax (data.y0, 0, 239);
minmax (data.y1, 0, 239);
if (data.x1 < data.x0) swap(data.x0,data.x1);
if (data.y1 < data.y0) swap(data.y0,data.y1);
#ifdef _LVGL
// com_addr[0] = ILI9341_PASET;
// com_data[0] = (319-data.x1) >> 8; // MSB LOWER
// com_data[1] = (319-data.x1) & 0xFF; // LSB LOWER
// com_data[2] = (319-data.x0) >> 8; // MSB UPPER
// com_data[3] = (319-data.x0) & 0xFF; // LSB UPPER
#else
com_addr[0] = ILI9341_PASET;
com_data[0] = (data.x0) >> 8; // MSB LOWER
com_data[1] = (data.x0) & 0xFF; // LSB LOWER
com_data[2] = (data.x1) >> 8; // MSB UPPER
com_data[3] = (data.x1) & 0xFF; // LSB UPPER
#endif
// command sequence is send command with A0 down, then data with A0 up.
// CS must remain active low throughout the transaction
#ifdef _SIMPLE
// command pointer says to send data with A0 down
if (A0.port != nullptr) A0.reset();
status = HAL_SPI_Transmit(SPI_interface, (unsigned char*) &com_addr[0], 1, 2);
// data pointer says to send data with A0 up
if (A0.port != nullptr) A0.set();
status = HAL_SPI_Transmit( SPI_interface,&com_data[0],4, 2);
#else
ILI9341_spi->Send(&com_addr[0], 1, &com_data[0], 4, CS_INACTIVE);
#endif
dx = abs(data.x1 - data.x0);
// dy = data.y1 - data.y0;
// build QVGA_image from QVGA, DMA2D can be called from RGB565 buffer
RGB565_BUFFER(translate, page, 0, 0, 320, 240); // QVGA_image now regenerated from main image in RGB565
for (int y = (data.y0); y <= (data.y1); y++)
{
// legal values are 0 to 239 because of rotation
// reverse Y direction to go top down on physical display
// for smart light board with LED strip at bottom
com_addr[0] = ILI9341_CASET;
com_data[0] = (y) >> 8; // MSB LOWER
com_data[1] = (y) & 0xFF; // LSB LOWER
com_data[2] = (y) >> 8; // MSB UPPER
com_data[3] = (y) & 0xFF; // LSB UPPER
// CASET writes from y0 to y1 inclusive, so y1 does not need to be incremented
#ifdef _SIMPLE
// command pointer says to send data with A0 down
if (A0.port != nullptr) A0.reset();
status = HAL_SPI_Transmit(SPI_interface, (unsigned char*) &com_addr[0], 1, 2);
// data pointer says to send data with A0 up
if (A0.port != nullptr) A0.set();
status = HAL_SPI_Transmit( SPI_interface,&com_data[0],4, 2);
#else
ILI9341_spi->Send(&com_addr[0], 1, &com_data[0], 4, CS_INACTIVE);
#endif
// fill line buffer with one line of data
// in RGB565 format
com_addr[0] = ILI9341_RAMWR;
#ifdef _SIMPLE
// command pointer says to send data with A0 down
if (A0.port != nullptr) A0.reset();
status = HAL_SPI_Transmit(SPI_interface, (unsigned char*) &com_addr[0], 1, 2);
#else
status = ILI9341_spi->Send(&com_addr[0], 1,
nullptr, 0, CS_INACTIVE);
#endif
if (A0.port != nullptr) A0.set();
#ifdef _SIMPLE
// data pointer says to send data with A0 up
// dx is low by one. i.e. start at 0 and stop at 1 is two rows in terms of input to routine
// transfer is in bytes because command is a byte, and SPI interface is set to bytes
#if (defined _ILI9341_DMA)
// RTOS_ILI9341[interface].tag = false;
// taskENTER_CRITICAL();
// status = HAL_SPI_Abort(SPI_interface);
// status =HAL_SPI_DMAStop(&hspi1);
// while (SPI_interface->State == HAL_SPI_STATE_BUSY_TX); // wait end of transfer
// result = HAL_SPI_Transmit_DMA(SPI_interface, (unsigned char*)&line_buffer[data.x0],(dx+1));
result = HAL_SPI_Transmit_DMA(SPI_interface, (unsigned char*)&QVGA_image.Lpixel[y][data.x0],(dx+1));
// taskEXIT_CRITICAL();
// while (hSPI1.State == HAL_SPI_STATE_); // wait end of transfer
// while (SPI_interface->State != HAL_SPI_STATE_READY); // wait end of transfer
//// status =HAL_SPI_DMAStop(&hspi1);
// result = HAL_SPI_Transmit_IT(SPI_interface, (unsigned char*)&line_buffer[data.x0],(dx+1)); // 2 bytes/pixel
// while (RTOS_ILI9341[interface].tag == false);
status = HAL_DMA_PollForTransfer(&handle_GPDMA1_Channel0, HAL_DMA_FULL_TRANSFER, 2);
// ensure DMA transfer is complete
while (status != HAL_OK)
{
status = HAL_DMA_PollForTransfer(&handle_GPDMA1_Channel0, HAL_DMA_FULL_TRANSFER, 2);
}
// AL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi)
status = HAL_DMA_Abort_IT(&handle_GPDMA1_Channel0); // stop DMA so that next use of SPI is valid and does not return HAL_BUSY
#elif (defined _ILI9341_IRQ)
// if IRQ is not generated, then this method does not work and hangs waiting for first
// interrupt.
// taskEXIT_CRITICAL();
RTOS_ILI9341[interface].tag = false;
// result = HAL_SPI_Transmit_IT(SPI_interface, (unsigned char*)&line_buffer[data.x0],(dx+1)); // 2 bytes/pixel
result = HAL_SPI_Transmit_IT(SPI_interface, (unsigned char*)&QVGA_image.Lpixel[y][data.x0],(dx)); // 2 bytes/pixel
while (RTOS_ILI9341[interface].tag == false);
#else
// failsafe blocking transfer.
// HAL_SPI_Transmit(SPI_interface, (unsigned char*)&line_buffer[data.x0],2*(dx+1), 2); // 2 bytes/pixel
// for (int jj = 0; jj < 2*(dx+1); jj+=10)
// for (int jj = 0; jj < 2*(dx+1); jj+=10)
// {
// HAL_SPI_Transmit(SPI_interface, (unsigned char*)&line_buffer[data.x0 + jj],10,2);
// HAL_SPI_Transmit(SPI_interface, (unsigned char*)&line_buffer[xx],1,2);
// vTaskDelay(10);
// }
// if translate is true, then RGB565 is called, and QVGA_image is the source
// if translate is false, then RGB565 is not called, and QVGA_image is the source
HAL_SPI_Transmit(SPI_interface, (unsigned char*)&QVGA_image.Lpixel[y][data.x0],2*(dx+1), 10); // 2 bytes/pixel
#endif
// }
#else
// status = ILI9341_spi->Send(nullptr, 0
// ,(uint8_t*) &line_buffer[data.x0],2*(dx+1), CS_INACTIVE);
#endif
} // end loop
break;
Since this is writing to a display, and the display address set is the whole width, line by line, I can see what happens on the display.
Programmed I/O works.
The first DMA transaction works, Poll for transfer returns HAL_OK.
Looping back to the first programmed transfer returns HAL_ERROR. Following the code through indicates that the State of the SPI interface is HAL_BUSY.
I’m missing something here, I think.
