cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 U(S)ART Low Level RS485-DE Pin not switching

CBerg
Senior

Hi Folks,

I have an issue with the RS485 Driver Enable Pin with the USART6 on an H7A3 (Nucleo).

The Perhiperal is set up in CubeMX with "Hardware Flow Control (RS485) enabled.

I have developed a driver using the Low Level functions.

The Peripheral is setup by Cube MX,  in "uart.c" the "DE Mode" is enabled:

 

  LL_USART_EnableDEMode(USART6);
  LL_USART_SetDESignalPolarity(USART6, LL_USART_DE_POLARITY_HIGH);
  LL_USART_SetDEAssertionTime(USART6, 0);
  LL_USART_SetDEDeassertionTime(USART6, 0);

 

When I start a transmission with

 

		LL_DMA_SetMemoryAddress(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, txAddr);		// set TxBuffer Address
		LL_DMA_SetDataLength(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, dataSz);			// set Tx Size

		LL_DMA_EnableIT_TC(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Complete IRQ
		LL_DMA_EnableIT_TE(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Error IRQ

		LL_USART_ClearFlag_TC(hrUA->hUA);											// clear Tx complete IRQ
		// NOTE: Transfer Complete IRQ will be enabled by DMA TC Interrupt handler
		LL_USART_EnableDMAReq_TX(hrUA->hUA);
		LL_USART_EnableDirectionTx(hrUA->hUA);										// enable U(S)ART Tx

 

I can see the Bits beeing clocked out on the Tx Pin in my Oscilloskope. The DMA Interrupt and the USART Transfer complete Interrupt are fired, so generally I'd say: the peripheral is working and is sending data. But the Scope shows clearly that the Driver Enable Pin is not toggling during TX.

My assumption was: when the "DE-Mode" is enabled (LL_USART_EnableDEMode(USART6);) an I enable the Transmission (LL_USART_EnableDirectionTx(hrUA->hUA);) the Peripheral would set the DE-Pin automatically - otherwise settings like DE Asserting-Time and DE Deassertion Time would not make much sense.

Am I missing something? Do I have to take an extra step to tell the Peripheral to enable the DE Pin? I was looking for something like that, but could not find anything ...

 

thank you for any input!

1 ACCEPTED SOLUTION

Accepted Solutions
CBerg
Senior

hmm ... i have no idea, why, but it is working now.

The working Code:

		LL_DMA_SetMemoryAddress(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, txAddr);		// set TxBuffer Address
		LL_DMA_SetDataLength(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, dataSz);			// set Tx Size
		do {
			LL_DMA_EnableStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);				// enable RX DMA stream
		} while(!(LL_DMA_IsEnabledStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh)));

		LL_DMA_EnableIT_TC(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Complete IRQ
		LL_DMA_EnableIT_TE(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Error IRQ

		LL_USART_ClearFlag_TC(hrUA->hUA);											// clear Tx complete IRQ
		// NOTe: Transfer Complete IRQ will be enabled by DMA TC Interrupt handler
		LL_USART_EnableDMAReq_TX(hrUA->hUA);
		LL_USART_EnableDirectionTx(hrUA->hUA);										// enable U(S)ART Tx

Setup is done automatically by Cube MX. Just select "LL" for the UART in the Project-Settings-Advance and configure it in the CubeMX as if you would configure it with HAL.

The obvious difference between the code I posted in my initial question and this code is the do () while loop. I forgot this piece of code in my initial posting. This code was there in my first attempts. So I see no difference, and I don't know why it is working now and did not work before.

All I did was a Project Clean

Just in case anyone is searching for that, this is the one-time initialisation of the Peripheral and the DMA Channels:

			LL_USART_DisableDirectionTx(hrUA->hUA);								// Disable U(S)ART Tx
			LL_USART_DisableDirectionRx(hrUA->hUA);								// Disable U(S)ART Rx
			uint32_t rxaddr = (uint32_t)(&UA_RxDummy);
			uint32_t txaddr = (uint32_t)(&UA_TxDummy);

			LL_DMA_DisableStream(hrUA->rxDMA.hDMA, hrUA->rxDMA.dmaCh);			// Disable DMA (Rx)
			LL_USART_DisableDMAReq_RX(hrUA->hUA);									// Remove DMA (Rx)
			// Configure RX
			// LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
			LL_DMA_ConfigAddresses(
					hrUA->rxDMA.hDMA,											// DMA Peripheral
					hrUA->rxDMA.dmaCh,											// DMA Channel
					LL_USART_DMA_GetRegAddr(hrUA->hUA, LL_USART_DMA_REG_DATA_RECEIVE),	// Source Address = RX Data register
					rxaddr,														// Destination Address = dummy
					LL_DMA_GetDataTransferDirection(							// Direction
							hrUA->rxDMA.hDMA,
							hrUA->rxDMA.dmaCh));

			LL_DMA_DisableStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);			// Disable DMA (Tx)
			LL_USART_DisableDMAReq_TX(hrUA->hUA);									// Remove DMA (Tx)
			// Configure TX
			// LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
			LL_DMA_ConfigAddresses(
					hrUA->txDMA.hDMA,											// DMA Peripheral
					hrUA->txDMA.dmaCh,											// DMA Channel
					txaddr,														// Source Address = dummy
					LL_USART_DMA_GetRegAddr(hrUA->hUA, LL_USART_DMA_REG_DATA_TRANSMIT),	// Destination Address = TX Data Register
					LL_DMA_GetDataTransferDirection(							// Direction
							hrUA->txDMA.hDMA,
							hrUA->txDMA.dmaCh));

			// clear Interrupt Status registers
			*hrUA->rxDMA.IFCR = hrUA->rxDMA.regmask.all;
			*hrUA->txDMA.IFCR = hrUA->txDMA.regmask.all;

 

It is a bit unsatisfying, when a issue solves itself and you don't know why, but on the other hand, it was one of the fastest solved "strange behaviour" bugs I had so far ...

thanks and cheers,

cb

View solution in original post

6 REPLIES 6
Uwe Bonnes
Principal III

Did you configure the DE pin for the proper alternate function?

CBerg
Senior

yes. This is done automatically by CubeMX. I checked that

Uwe Bonnes
Principal III

If you have triple checked the schematics, layout, soldering and setup and thinsg still do not work, enter your code in the debugger, read out the GPIO and USART peropheral registers and compare the bits with what you expect.

CBerg
Senior

ok, thanks for your input, Uwe.

May I interpret your answers in that direction, that you'd also expect the peripheral to set the DE pin automatically as soon as the transfer starts?

Looks like I have cought me a "strange behaviour" bug ... again. Looks like I gonna invest some time to find out where this little su*ker is hiding ...

 

CBerg
Senior

hmm ... i have no idea, why, but it is working now.

The working Code:

		LL_DMA_SetMemoryAddress(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, txAddr);		// set TxBuffer Address
		LL_DMA_SetDataLength(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh, dataSz);			// set Tx Size
		do {
			LL_DMA_EnableStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);				// enable RX DMA stream
		} while(!(LL_DMA_IsEnabledStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh)));

		LL_DMA_EnableIT_TC(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Complete IRQ
		LL_DMA_EnableIT_TE(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);					// enable Tx Transfer Error IRQ

		LL_USART_ClearFlag_TC(hrUA->hUA);											// clear Tx complete IRQ
		// NOTe: Transfer Complete IRQ will be enabled by DMA TC Interrupt handler
		LL_USART_EnableDMAReq_TX(hrUA->hUA);
		LL_USART_EnableDirectionTx(hrUA->hUA);										// enable U(S)ART Tx

Setup is done automatically by Cube MX. Just select "LL" for the UART in the Project-Settings-Advance and configure it in the CubeMX as if you would configure it with HAL.

The obvious difference between the code I posted in my initial question and this code is the do () while loop. I forgot this piece of code in my initial posting. This code was there in my first attempts. So I see no difference, and I don't know why it is working now and did not work before.

All I did was a Project Clean

Just in case anyone is searching for that, this is the one-time initialisation of the Peripheral and the DMA Channels:

			LL_USART_DisableDirectionTx(hrUA->hUA);								// Disable U(S)ART Tx
			LL_USART_DisableDirectionRx(hrUA->hUA);								// Disable U(S)ART Rx
			uint32_t rxaddr = (uint32_t)(&UA_RxDummy);
			uint32_t txaddr = (uint32_t)(&UA_TxDummy);

			LL_DMA_DisableStream(hrUA->rxDMA.hDMA, hrUA->rxDMA.dmaCh);			// Disable DMA (Rx)
			LL_USART_DisableDMAReq_RX(hrUA->hUA);									// Remove DMA (Rx)
			// Configure RX
			// LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
			LL_DMA_ConfigAddresses(
					hrUA->rxDMA.hDMA,											// DMA Peripheral
					hrUA->rxDMA.dmaCh,											// DMA Channel
					LL_USART_DMA_GetRegAddr(hrUA->hUA, LL_USART_DMA_REG_DATA_RECEIVE),	// Source Address = RX Data register
					rxaddr,														// Destination Address = dummy
					LL_DMA_GetDataTransferDirection(							// Direction
							hrUA->rxDMA.hDMA,
							hrUA->rxDMA.dmaCh));

			LL_DMA_DisableStream(hrUA->txDMA.hDMA, hrUA->txDMA.dmaCh);			// Disable DMA (Tx)
			LL_USART_DisableDMAReq_TX(hrUA->hUA);									// Remove DMA (Tx)
			// Configure TX
			// LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
			LL_DMA_ConfigAddresses(
					hrUA->txDMA.hDMA,											// DMA Peripheral
					hrUA->txDMA.dmaCh,											// DMA Channel
					txaddr,														// Source Address = dummy
					LL_USART_DMA_GetRegAddr(hrUA->hUA, LL_USART_DMA_REG_DATA_TRANSMIT),	// Destination Address = TX Data Register
					LL_DMA_GetDataTransferDirection(							// Direction
							hrUA->txDMA.hDMA,
							hrUA->txDMA.dmaCh));

			// clear Interrupt Status registers
			*hrUA->rxDMA.IFCR = hrUA->rxDMA.regmask.all;
			*hrUA->txDMA.IFCR = hrUA->txDMA.regmask.all;

 

It is a bit unsatisfying, when a issue solves itself and you don't know why, but on the other hand, it was one of the fastest solved "strange behaviour" bugs I had so far ...

thanks and cheers,

cb

Uwe Bonnes
Principal III

Yes, if set up right and no hardware error, DE is set automatic. I have done so from some device families. H7A as a recent family  offers more changeable parameters, e.g. the RTS/DE timing but will work too.