cancel
Showing results for 
Search instead for 
Did you mean: 

Nucleo-F767ZI + Zephyr: get UART Async API sample working with DMA?

digitalone
Associate II

Zephyr RTOS 4.3.

I am trying to get this sample working on my STM32 Nucleo F767ZI board:
zephyr/samples/drivers/uart/async_api/

I created an overlay file.

nucleo_f767zi.overlay

 

dut: &usart3 {
dmas = <&dma1 2 STM32_DMA_PERIPH_TX>,
<&dma1 3 STM32_DMA_PERIPH_RX>;
dma-names = "tx", "rx";
};

&dma1 {
status = "okay";
};

 

Building and running the sample I get the following output:

 

*** Booting Zephyr OS build v4.3.0-929-g1d6e0d533a81 ***
[00:00:05.000,000] <inf> sample: Loop 0: Sending 3 packets
[00:00:05.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:05.000,000] <err> sample: Unknown error (-14)
[00:00:05.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:05.000,000] <err> sample: Unknown error (-14)
[00:00:05.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:05.000,000] <err> sample: Unknown error (-14)
[00:00:05.000,000] <inf> sample: RX is now enabled

 

I then updated my prj.conf adding nocache support:
prj.conf

 

CONFIG_LOG=y
CONFIG_NET_BUF=y
CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NOCACHE_MEMORY=y

 

I then pulled over the macro definition for this line:

 

NET_BUF_POOL_DEFINE(tx_pool, LOOP_ITER_MAX_TX, MAX_TX_LEN, 0, NULL);

 

And changed:

 

static uint8_t __noinit net_buf_data_##_name[_count][_data_size] __net_buf_align;

 

to:

 

static uint8_t __nocache net_buf_data_##_name[_count][_data_size] __net_buf_align;

 

Thus putting the Tx buffer in nocache memory, but now I am getting these errors:

 

*** Booting Zephyr OS build v4.3.0-929-g1d6e0d533a81 ***
[00:00:05.000,000] <inf> sample: Loop 0: Sending 3 packets
[00:00:05.000,000] <err> dma_stm32: Memcopy not supported for device dma@40026000
[00:00:05.000,000] <err> uart_stm32: dma tx config error!
[00:00:05.000,000] <err> sample: Unknown error (-22)
[00:00:05.000,000] <dbg> sample: main: Queuing buffer 0x20022458
[00:00:05.000,000] <dbg> sample: main: Queuing buffer 0x20022470
[00:00:05.000,000] <inf> sample: RX is now enabled
[00:00:06.044,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:06.044,000] <dbg> sample: uart_callback: TX complete 0
[00:00:06.044,000] <err> dma_stm32: Memcopy not supported for device dma@40026000
[00:00:06.044,000] <err> uart_stm32: dma tx config error!
[00:00:06.044,000] <err> sample: TX from ISR failed (-22)
[00:00:07.076,000] <dbg> sample: uart_callback: EVENT: 0

 

I also noticed in my build output the messages:

 

/home/myuser/Projects/uart_async_api/build/primary/zephyr/zephyr.dts:550.4-551.31: Warning (dmas_property): /soc/serial@40004800:dmas: cell 5 is not a phandle reference
/home/myuser/Projects/uart_async_api/build/primary/zephyr/zephyr.dts:550.4-551.31: Warning (dmas_property): /soc/serial@40004800:dmas: Could not get phandle node for (cell 5)

 

Is the above related to the issues I am seeing?

Does the STM32 Zephyr driver support the UART Async API?
If so, how can I get it working?

Thank you.

6 REPLIES 6
T_Hamdi
ST Employee

hello @digitalone 

Regarding your question: Does the STM32 Zephyr driver support the UART Async API? 

Yes, it does support the UART Async API, provided that:

  • The Device Tree must correctly describe the dmas for the UART.
  • The buffers used by the DMA must respect the cache constraints (placed in __nocache or an equivalent non cacheable region).
CONFIG_LOG=y
CONFIG_NET_BUF=y
CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y
CONFIG_TEST_RANDOM_GENERATOR=y

CONFIG_DMA=y
CONFIG_NOCACHE_MEMORY=y
CONFIG_NOCACHE_MEMORY_STATIC=y

also, to fix the issues you are seeing:

Correct the DTS overlay so that it complies with the Zephyr binding for the STM32 DMA v2 implementation:

Zephyr implementation st,stm32-dma-v2  

Example:

&usart3 {
    status = "okay";
    current-speed = <115200>;

    dmas = <&dma1 2 1 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH)>,
           <&dma1 3 1 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>;
    dma-names = "tx", "rx";
};

&dma1 {
    status = "okay";
};

with these adjustments, the samples/drivers/uart/async_api/ example works on the Nucleo-F767ZI with UART3 + DMA, with no DTS warnings and no DMA/UART driver errors.

best regrads,

Hamdi

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb

Thank you for the reply.

I am getting compile errors now.

It occurs as soon as I add "CONFIG_NOCACHE_MEMORY_STATIC=y" to the prj.conf file.

I cannot find it defined anywhere, what does it do?

If I comment out the above and update the device tree overlay with what you provided above I get this error: 

devicetree error: <Node /clocks/pll in ~/zephyrproject/zephyr/dts/arm/st/f7/stm32f7.dtsi:87> lacks #dma-cells

I don't understand this as when I look in that file I do see dma-cells.

T_Hamdi
ST Employee

Hello @digitalone 

In your Zephyr 4.3 + STM32F7 setup, CONFIG_NOCACHE_MEMORY_STATIC is not defined.
That option exists only on some SoCs/boards; it is not universal.

The error:

devicetree error: <Node /clocks/pll in .../stm32f7.dtsi:87> lacks #dma-cells

After checking, you need to adapt this to DMA v1 (st, stm32-dma-v1, #dma-cells = <4>) instead of v2.
For v1, each dmas entry must have 4 integers after the phandle.

A corrected version for DMA v1is:

&usart3 {
    status = "okay";
    current-speed = <115200>;

    dmas = <&dma1 2 4 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH | STM32_DMA_MEMORY_INC) 0>,
           <&dma1 3 4 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH | STM32_DMA_MEMORY_INC) 0>;
    dma-names = "tx", "rx";
};

&dma1 {
    status = "okay";
};

 best regards,  

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb

Thank you for the reply.

I was getting device tree errors with the above so I had to remove STM32_DMA_MEMORY_INC from both of them as shown below. VSCode was underlining them with red squiggles in addition to the error.

&usart3 {
status = "okay";
current-speed = <115200>;

dmas = <&dma1 2 4 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) 0>,
<&dma1 3 4 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH) 0>;
dma-names = "tx", "rx";
};

&dma1 {
status = "okay";
};

I was able to build and run it but am seeing some errors.  For example "<err> uart_stm32: dma tx config error!"

See the serial output below.  Why am I getting these errors?

---- Opened the serial port /dev/ttyACM0 ----
*** Booting Zephyr OS build v4.3.0-929-g1d6e0d533a81 ***
[00:00:05.000,000] <inf> sample: Loop 0: Sending 4 packets
[00:00:05.000,000] <dbg> sample: main: Queuing buffer 0x20022458
[00:00:05.000,000] <dbg> sample: main: Queuing buffer 0x20022470
[00:00:05.000,000] <dbg> sample: main: Queuing buffer 0x20022488
[00:00:05.000,000] <dbg> sample: uart_callback: EVENT: 2
[00:00:05.000,000] <inf> sample: RX_RDY
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |........ ........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |........ ........
[00:00:05.000,000] <dbg> sample: uart_callback: EVENT: 3
[00:00:05.000,000] <dbg> sample: uart_callback: Providing buffer index 1
[00:00:05.000,000] <inf> sample: RX is now enabled
[00:00:05.000,000] <dbg> sample: uart_callback: EVENT: 4
[00:00:05.000,000] <dbg> sample: uart_callback: EVENT: 4
[00:00:05.000,000] <dbg> sample: uart_callback: EVENT: 5
[00:00:05.088,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:05.088,000] <dbg> sample: uart_callback: TX complete 0x20022440
[00:00:05.088,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:05.088,000] <err> uart_stm32: dma tx config error!
[00:00:05.088,000] <err> sample: TX from ISR failed (-22)
[00:00:06.119,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:06.119,000] <dbg> sample: uart_callback: TX complete 0
[00:00:06.119,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:06.119,000] <err> uart_stm32: dma tx config error!
[00:00:06.119,000] <err> sample: TX from ISR failed (-22)
[00:00:07.149,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:07.149,000] <dbg> sample: uart_callback: TX complete 0
[00:00:07.149,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:07.149,000] <err> uart_stm32: dma tx config error!
[00:00:07.149,000] <err> sample: TX from ISR failed (-22)
[00:00:08.179,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:08.179,000] <dbg> sample: uart_callback: TX complete 0
[00:00:10.000,000] <inf> sample: Loop 1: Sending 3 packets
[00:00:10.000,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:10.000,000] <err> uart_stm32: dma tx config error!
[00:00:10.000,000] <err> sample: Unknown error (-22)
[00:00:10.000,000] <dbg> sample: main: Queuing buffer 0x20022470
[00:00:10.000,000] <dbg> sample: main: Queuing buffer 0x20022458
[00:00:10.000,000] <dbg> sample: uart_callback: EVENT: 5
[00:00:10.000,000] <inf> sample: RX is now disabled
[00:00:11.048,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:11.048,000] <dbg> sample: uart_callback: TX complete 0
[00:00:11.048,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:11.048,000] <err> uart_stm32: dma tx config error!
[00:00:11.048,000] <err> sample: TX from ISR failed (-22)
[00:00:12.078,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:12.078,000] <dbg> sample: uart_callback: TX complete 0
[00:00:12.078,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:12.078,000] <err> uart_stm32: dma tx config error!
[00:00:12.078,000] <err> sample: TX from ISR failed (-22)
[00:00:13.108,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:13.108,000] <dbg> sample: uart_callback: TX complete 0
[00:00:15.000,000] <inf> sample: Loop 2: Sending 4 packets
[00:00:15.000,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:15.000,000] <err> uart_stm32: dma tx config error!
[00:00:15.000,000] <err> sample: Unknown error (-22)
[00:00:15.000,000] <dbg> sample: main: Queuing buffer 0x20022470
[00:00:15.000,000] <dbg> sample: main: Queuing buffer 0x20022440
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 0
[00:00:16.037,000] <dbg> sample: uart_callback: TX complete 0
[00:00:16.037,000] <err> dma_stm32: dma stream 2 is busy.
[00:00:16.037,000] <err> uart_stm32: dma tx config error!
[00:00:16.037,000] <err> sample: TX from ISR failed (-22)
[00:00:16.037,000] <dbg> sample: main: Queuing buffer 0x20022470
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 2
[00:00:16.037,000] <inf> sample: RX_RDY
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |........ ........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |........ ........
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 3
[00:00:16.037,000] <dbg> sample: uart_callback: Providing buffer index 1
[00:00:16.037,000] <inf> sample: RX is now enabled
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 4
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 4
[00:00:16.037,000] <dbg> sample: uart_callback: EVENT: 5
---- Closed the serial port /dev/ttyACM0 ----

 

T_Hamdi
ST Employee

Hello @digitalone 

Please correct your DTS file with these two lines, according to the reference manual.

dmas = <&dma1 3 4 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH | STM32_DMA_MEM_INC) 0>,
       <&dma1 1 4 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH | STM32_DMA_MEM_INC) 0>;

 best regards,

 hamdi

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb

Thank you.  That fixed the output.  

Now I need help with what I was experiencing at the beginning.

With the default code below for "tx_pool"

/* Maximum number of packets to generate per iteration */
#define LOOP_ITER_MAX_TX 4
/* Maximum size of our TX packets */
#define MAX_TX_LEN 32
#define RX_CHUNK_LEN 32

/* Buffer pool for our TX payloads */
NET_BUF_POOL_DEFINE(tx_pool, LOOP_ITER_MAX_TX, MAX_TX_LEN, 0, NULL);

struct k_fifo tx_queue;

 I get the following errors:

---- Opened the serial port /dev/ttyACM0 ----
[00:00:05.000,000] <inf> sample: Loop 0: Sending 1 packets
[00:00:05.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:05.000,000] <err> sample: Unknown error (-14)
[00:00:05.000,000] <err> uart_stm32: Rx buffer should be placed in a nocache memory region
[00:00:05.000,000] <inf> sample: RX is now enabled
[00:00:10.000,000] <inf> sample: Loop 1: Sending 3 packets
[00:00:10.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:10.000,000] <err> sample: Unknown error (-14)
[00:00:10.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:10.000,000] <err> sample: Unknown error (-14)
[00:00:10.000,000] <err> uart_stm32: Tx buffer should be placed in a nocache memory region
[00:00:10.000,000] <err> sample: Unknown error (-14)
[00:00:10.000,000] <inf> sample: RX is now disabled
---- Closed the serial port /dev/ttyACM0 ----

To fix this issue I had to modify the code as followed to apply the __nocache attribute.

/* Maximum number of packets to generate per iteration */
#define LOOP_ITER_MAX_TX 4
/* Maximum size of our TX packets */
#define MAX_TX_LEN 32
#define RX_CHUNK_LEN 32

// #define _NET_BUF_ARRAY_DEFINE(_name, _count, _ud_size)					       \
// 	struct _net_buf_##_name { uint8_t b[sizeof(struct net_buf)];			       \
// 				  uint8_t ud[_ud_size]; } __net_buf_align;		       \
// 	BUILD_ASSERT(_ud_size <= UINT8_MAX);						       \
// 	BUILD_ASSERT(offsetof(struct net_buf, user_data) ==				       \
// 		     offsetof(struct _net_buf_##_name, ud), "Invalid offset");		       \
// 	BUILD_ASSERT(__alignof__(struct net_buf) ==					       \
// 		     __alignof__(struct _net_buf_##_name), "Invalid alignment");	       \
// 	BUILD_ASSERT(sizeof(struct _net_buf_##_name) ==					       \
// 		     ROUND_UP(sizeof(struct net_buf) + _ud_size, __alignof__(struct net_buf)), \
// 		     "Size cannot be determined");					       \
// 	static struct _net_buf_##_name _net_buf_##_name[_count] __noinit

struct _net_buf_tx_pool { uint8_t b[sizeof(struct net_buf)];
				uint8_t ud[0]; } __net_buf_align;
static struct _net_buf_tx_pool _net_buf_tx_pool[LOOP_ITER_MAX_TX] __noinit;


// #define NET_BUF_POOL_FIXED_DEFINE(_name, _count, _data_size, _ud_size, _destroy) \
// 	_NET_BUF_ARRAY_DEFINE(_name, _count, _ud_size);                        \
// 	static uint8_t __noinit net_buf_data_##_name[_count][_data_size] __net_buf_align; \
// 	static const struct net_buf_pool_fixed net_buf_fixed_##_name = {       \
// 		.data_pool = (uint8_t *)net_buf_data_##_name,                  \
// 	};                                                                     \
// 	static const struct net_buf_data_alloc net_buf_fixed_alloc_##_name = { \
// 		.cb = &net_buf_fixed_cb,                                       \
// 		.alloc_data = (void *)&net_buf_fixed_##_name,                  \
// 		.max_alloc_size = _data_size,                                  \
// 	};                                                                     \
// 	static STRUCT_SECTION_ITERABLE(net_buf_pool, _name) =                  \
// 		NET_BUF_POOL_INITIALIZER(_name, &net_buf_fixed_alloc_##_name,  \
// 					 _net_buf_##_name, _count, _ud_size,   \
// 					 _destroy)

static uint8_t __nocache net_buf_data_tx_pool[LOOP_ITER_MAX_TX][MAX_TX_LEN] __net_buf_align;
static const struct net_buf_pool_fixed net_buf_fixed_tx_pool = {
	.data_pool = (uint8_t *)net_buf_data_tx_pool,
}; 
static const struct net_buf_data_alloc net_buf_fixed_alloc_tx_pool = {
	.cb = &net_buf_fixed_cb,
	.alloc_data = (void *)&net_buf_fixed_tx_pool,
	.max_alloc_size = MAX_TX_LEN,
}; 
static STRUCT_SECTION_ITERABLE(net_buf_pool, tx_pool) = NET_BUF_POOL_INITIALIZER(tx_pool, &net_buf_fixed_alloc_tx_pool, _net_buf_tx_pool, LOOP_ITER_MAX_TX, 0, NULL);

/* Buffer pool for our TX payloads */
//NET_BUF_POOL_DEFINE(tx_pool, LOOP_ITER_MAX_TX, MAX_TX_LEN, 0, NULL);

struct k_fifo tx_queue;
struct net_buf *tx_pending_buffer;
__nocache uint8_t async_rx_buffer[2][RX_CHUNK_LEN];
volatile uint8_t async_rx_buffer_idx;

 

Is there a way to apply __nocache to the "NET_BUF_POOL_DEFINE(tx_pool, LOOP_ITER_MAX_TX, MAX_TX_LEN, 0, NULL);" line other than what I did, which was getting the source code for the  "NET_BUF_POOL_DEFINE" macro and unpacking it and finding the write place to put the __nocache?

 It seems like there should be a better way but I could not find one.