cancel
Showing results for 
Search instead for 
Did you mean: 

DMA to UART TX , code works on NUCLEO STM32H743 but not DISCO STM32H745

bnguy.1
Associate III

On both boards the UART/DMA in CubeMX is setup the same, with a DMA channel added for "USART3_TX". Comparing the generated USART and DMA initialization code, they are identical.

However, with the NUCLEO board, it transmits with either "HAL_UART_Transmit()" or "HAL_DMA_Start_IT()".

But on the DISCO board, it only transmits if using "HAL_UART_Transmit()", NOT "HAL_DMA_Start_IT()" nor "HAL_UART_Transmit_DMA()"

I verified that the DISCO is calling MX_DMA_Init to enable the DMA clock/NVICs.. just like the NUCLEO board, and all the HAL routines return "HAL_OK".

The only other difference is that the DISCO is a dual-core arm (CM7 and CM4), but I've disabled the CM4 but maybe there's some other caching , DMA/UART-TX domain issue?

7 REPLIES 7
TDK
Guru

There's no reason it shouldn't work. Ensure the function returns HAL_OK. If it does, examine registers to see where it's hung up.

Are you compiling the same code for each? Or are you using the same HEX file for both? Might be able to run the H743 HEX file on the H745 directly. There are some differences in startup, but it may work.

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

Check RAM addresses of the buffers involved​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
bnguy.1
Associate III

All the HAL routines return "HAL_OK". I've tried downloading the NUCLEO project onto \the DISCO but it fails during the SystemClock_Config(). (The DISCO has a 25Mhz clock whereas the NUCLEO has an 8Mhz input clock). In both CUBEMX settings, the core and peripheral clocks are the same for both projects.

The address for the DMA -> UART TX source is a local variable, which seems like it could be an issue, but the NUCLEO board has no problem with it. However, Just to be safe, I made it a global, and it still works for the NUCLEO, and still does not work with the DISCO board.

strncpy ( cDbgMsg, "Ready USART3\r\n\0", strlen("Ready USART3\r\n\0") );
 
// Set DMA as source of UART Tx Buffer 
huart3.Instance->CR3 |= USART_CR3_DMAT;  
 
HAL_DMA_RegisterCallback ( &hdma_usart3_tx, HAL_DMA_XFER_CPLT_CB_ID , &DMA_USART3_Complete_ISR);
 
HAL_DMA_Start_IT   (&hdma_usart3_tx , (uint32_t)(cDbgMsg),   (uint32_t)&huart3.Instance->TDR, 10 ) ;
 
HAL_UART_Transmit_DMA ( &huart3 , (uint8_t*)(cDbgMsg), strnlen (cDbgMsg, 16) );   

Looking at the pertinent DISCO Uart and DMA registers, it seems like the settings are all there:

0693W000003PbpXQAS.png

Make sure the HSE_VALUE in the code matches what the crystal actually is.
If you feel a post has answered your question, please click "Accept as Solution".
bnguy.1
Associate III

Upon further investigation, after the HAL_DMA_Start_IT  call (HAL_OK), the DMA2_Stream0_IRQHandler interrupt fires! But apparently , inside that HAL ISR, it has a Transmit Error which is the reason why the DISCO's DMA USART TX Complete ISR is never called.

if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
 {
  /* Transfer Error Interrupt management ***************************************/
  if ((tmpisr_dma & (DMA_FLAG_TEIF0_4 << (hdma->StreamIndex & 0x1FU))) != 0U)
  {
   if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TE) != 0U)
   {
    /* Disable the transfer error interrupt */
    ((DMA_Stream_TypeDef  *)hdma->Instance)->CR &= ~(DMA_IT_TE);
 
    /* Clear the transfer error flag */
    regs_dma->IFCR = DMA_FLAG_TEIF0_4 << (hdma->StreamIndex & 0x1FU);
 
    /* Update error code */
    hdma->ErrorCode |= HAL_DMA_ERROR_TE;
   }
  }

Seems the root problem is this declaration isn't placing the array into the D2 Memory , but rather DTCMRAM (0x20000080):

__attribute__ ((section(".SRAM2"), used))  ALIGN_32BYTES (uint8_t  cTxBuffer[64]);
 

Despite the STM32H745XIHX_FLASH.ld linker script having the above SRAM2 section mapped to 0x30000000

MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K  /* 2048? */
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K   /* 512k? */
RAM_D2 (xrw)      : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw)      : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw)      : ORIGIN = 0x00000000, LENGTH = 64K
}
 
...
 
  .SRAM2 ORIGIN(RAM_D2) (NOLOAD) : 
  {
    . = ALIGN(4);
    *(.buffers*)
   } > RAM_D2

 The NUCLEO has the same declaration and works fine.. Any idea why it's not mapping using the DISCO board?

In STM32CubeIDE you should right-click on project name -> Properties -> C/C++ Build -> Tool Settings -> MCU G/G++ Linker -> General and

unchek "Discard unused sectoins (-WI, --gc-sections)"

That worked for me