[RTD400 MCAL] K312 UART DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[RTD400 MCAL] K312 UART DMA

[RTD400 MCAL] K312 UART DMA

kerryzhou_0-1728211134400.png

 

1. Abstract

This article also explains the S32DS+EB configuration, RTD400. The MCAL training of other modules will be based on this structure in the future. However, this article will provide a command line version of the code. If you need the command line mode, you can directly copy one under the RTD MCAL code package and use VScode to compile it. The hardware of this article is based on K312-miniEVB, and the board situation is as follows:     

1.png

Fig 1

Function: In the K312 MCAL code, the UART transceiver function is implemented using DMA.

Since RTD400 does not have K312 routines, there is also a process of porting from RTD400 to K312 MCAL. Of course, the previous article has explained it very clearly, and also provided the S32DS project template. This article will be based on the previous S32DS EB project template. 

2. Function Implementation

2.1 K312 MINIEVB hardware configuration

For the hardware configuration, since this article only uses UART, the structure is very simple, using the pins:

LPUART3_TX: PTD2

LPUART3_RX: PTD3

and an external TTL-USB tool to achieve signal communication.

2.2 EB Configuration

    Here we list all the modules used in EB tresos related to this article, and focus on the modules that require specific configuration.

2.png

Fig 2

2.2.1 Mcl module

The Dma Logic Channel interface needs to be configured. The main purpose is to configure two DMA channels for LPUART3_TX and RX.

(1)dmalogicChannel_Type_0

3.png

Fig 3

(2)dmalogicChannel_Type_2

4.png

Fig 4

The callback registered here can also be called directly in the code.

2.2.2 Mcu module

Mcu->McuClockSettingConfig->McuClockReferencePoint->Lpuart3_clk

5.png

Fig 5

In fact, it configures the clock source frequency of LPUART to 24Mhz, which comes from AIPS_SLOW_CLK.

2.2.3 Platform module

Platform->Interrupt Controller->IntCtrlConfig,Configure 3 channels:

6.png

Fig 6

Here we only need to pay attention to the LPUART3 interrupt, as well as the DMA0 channel 6 and channel 7 interrupts, because these two DMA channels are configured for UART TX and RX. FlexIO is ignored, it is just a matter of whether it is deleted in the original routine.

2.2.4 Port module

Port->PortContainer, add PTD2,PTD3 pins:

7.png

Fig 7

8.png

Fig 8

2.2.5 Uart module

There are two places to configure:

(1)uart->General

9.png

Fig 9

(2)uart->uartChannel

10.png

Fig 10

There are 4 points to note here:

Point 1: Select the clock source configured in the mcu

Point 2: Configure the baud rate to 115200

Point 3: Select the asynchronous mode as DMA

Point 4: Select the two DMA channels configured in the mcl, and you need to match TX and RX to the corresponding DMA channels.

2.2.6 Rm module

Rm->DMA MUX

Configure 2 DMA_MUX channels:

11.png

Fig 11

12.png

Fig 12

2.3 main code

 

#include "Mcl.h"
#include "Mcu.h"
#include "CDD_Uart.h"
#include "CDD_Rm.h"
#include "Port.h"
#include "Platform.h"
#include "Lpuart_Uart_Ip_Irq.h"
#include "Flexio_Uart_Ip_Irq.h"
//#include "check_example.h"
#include <string.h>
#include "Port_Cfg.h"

#define UART_LPUART_INTERNAL_CHANNEL  0U
#define UART_FLEXIO_TX_CHANNEL  1U
#define UART_FLEXIO_RX_CHANNEL  2U

/* Welcome messages displayed at the console */
#define WELCOME_MSG "MCAL UART DMA Helloworld for automotive with S32K312!\r\n"
/* Error message displayed at the console, in case data is received erroneously */
#define ERROR_MSG "An error occurred! The application will stop!\r\n"

/* Length of the message to be received from the console */
#define MSG_LEN  50U
#define UART_BUFFER_LENGTH		((uint32)10U)
Std_ReturnType T_Uart_Status;
//uint8 Rx_Buffer[UART_BUFFER_LENGTH];

#define UART_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Uart_Memmap.h"
__attribute__(( aligned(32) )) uint8 Rx_Buffer[UART_BUFFER_LENGTH];
#define UART_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Uart_Memmap.h"

uint32 g_Uart_CallbackCounter = 0U;

uint32 g_DmaCh16_ErrorCallbackCounter = 0U;
uint32 g_DmaCh17_ErrorCallbackCounter = 0U;

//void Uart_Callback (void);
void Uart_Callback(const uint8 HwInstance, const Lpuart_Uart_Ip_EventType Event, void *UserData);

void Mcl_DmaCh16_ErrorCallback (void);
void Mcl_DmaCh17_ErrorCallback (void);
void Uart_Callback(const uint8 HwInstance, const Lpuart_Uart_Ip_EventType Event, void *UserData)
{
	if(Event == LPUART_UART_IP_EVENT_END_TRANSFER)
	{
		__asm volatile ("nop");
		__asm volatile ("nop");
		__asm volatile ("nop");
		__asm volatile ("nop");
		__asm volatile ("nop");
		__asm volatile ("nop");
	}
	else if (Event == LPUART_UART_IP_EVENT_TX_EMPTY)
	{
		__asm volatile ("nop");
		__asm volatile ("nop");
	}
	else if (Event == LPUART_UART_IP_EVENT_RX_FULL)
	{
		__asm volatile ("nop");
	}
	else if (Event == LPUART_UART_IP_EVENT_ERROR)
	{
		__asm volatile ("nop");
	}
	else
	{
		__asm volatile ("nop");
	}
}

void Mcl_DmaCh6_ErrorCallback (void)
{
	g_DmaCh16_ErrorCallbackCounter++;
}

void Mcl_DmaCh7_ErrorCallback (void)
{
	g_DmaCh17_ErrorCallbackCounter++;
}

boolean User_Str_Cmp(const uint8 * pBuffer1, const uint8 * pBuffer2, const uint32 length)
{
    uint32 idx = 0;
    for (idx = 0; idx < length; idx++)
    {
        if(pBuffer1[idx] != pBuffer2[idx])
        {
            return FALSE;
        }
    }
    return TRUE;
}
/**
* @brief        Main function of the example
* @details      Initializez the used drivers and uses the Icu
*               and Dio drivers to toggle a LED on a push button
*/
int main(void)
{
    Std_ReturnType   UartStatus = E_NOT_OK;
    uint32           RemainingBytes;
	uint32           Timeout   = 0xFFFFFF;
    Uart_StatusType  UartReceiveStatus  = UART_STATUS_TIMEOUT;
    Uart_StatusType  UartTransmitStatus = UART_STATUS_TIMEOUT;
    /* Initialize the Mcu driver */
    Mcu_Init(NULL_PTR);
    Mcu_InitClock(McuClockSettingConfig_0);
    Mcu_SetMode(McuModeSettingConf_0);
    /* Initialize Mcl module */
    Mcl_Init(NULL_PTR);
    /* Initialize Rm driver for using DmaMux*/
    Rm_Init (NULL_PTR);
    /* Initialize all pins using the Port driver */
    Port_Init(NULL_PTR);
    /* Initialize IRQs */
    Platform_Init(NULL_PTR);
    /* Initializes an UART driver*/
    Uart_Init(NULL_PTR);
     T_Uart_Status = Uart_AsyncSend(UART_LPUART_INTERNAL_CHANNEL, (const uint8 *)WELCOME_MSG, strlen(WELCOME_MSG));
        if (E_OK == T_Uart_Status)
        {
			do
			{
				/* Get transmission status */
				UartTransmitStatus = Uart_GetStatus (UART_LPUART_INTERNAL_CHANNEL, &RemainingBytes, UART_SEND);
			}
			while (UART_STATUS_NO_ERROR != UartTransmitStatus && 0 < Timeout--);

			Timeout = 0xFFFFFF;
			UartTransmitStatus = UART_STATUS_TIMEOUT;
        }

	for(;;)
    {
    	/* Receive data from the PC - Get 10 bytes in total */
    	UartStatus = Uart_AsyncReceive (UART_LPUART_INTERNAL_CHANNEL, Rx_Buffer, UART_BUFFER_LENGTH);

        if (E_OK == UartStatus)
        {
			do
			{
				/* Get receive status */
				UartReceiveStatus = Uart_GetStatus (UART_LPUART_INTERNAL_CHANNEL, &RemainingBytes, UART_RECEIVE);
			}
			while (UART_STATUS_NO_ERROR != UartReceiveStatus && 0 < Timeout--);

			Timeout = 0xFFFFFF;
			UartReceiveStatus = UART_STATUS_TIMEOUT;
        }
        UartStatus = E_NOT_OK;

    	/* Send data to the PC - Echo back the received data */
    	UartStatus = Uart_AsyncSend (UART_LPUART_INTERNAL_CHANNEL, Rx_Buffer, UART_BUFFER_LENGTH);

        if (E_OK == UartStatus)
        {
			do
			{
				/* Get transmission status */
				UartTransmitStatus = Uart_GetStatus (UART_LPUART_INTERNAL_CHANNEL, &RemainingBytes, UART_SEND);
			}
			while (UART_STATUS_NO_ERROR != UartTransmitStatus && 0 < Timeout--);
			Timeout = 0xFFFFFF;
			UartTransmitStatus = UART_STATUS_TIMEOUT;
        }
        UartStatus = E_NOT_OK;
    }
    Uart_Deinit();
    Mcl_DeInit();
 //   Exit_Example((T_Uart_Status1 == E_OK) && (T_Uart_Status2 == E_OK));
    return (0U);
}

 

It should be noted here that according to RTD C:\NXP\SW32K3_S32M27x_RTD_R21-11_4.0.0\eclipse\plugins\Uart_TS_T40D34M40I0R0\doc的RTD_UART_IM.pdf, RTD_UART_UM.pdf.

13.png

Fig 13

When doing DMA transfer, the buffer needs to be placed in the noncacheable area.

That's why this article is:

 

#define UART_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Uart_Memmap.h"
__attribute__(( aligned(32) )) uint8 Rx_Buffer[UART_BUFFER_LENGTH];
#define UART_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Uart_Memmap.h"

 

3. Test Result

Use UART3, pin UART3_TX:PTD2, UART3_RX:PTD3

After the chip is reset, send first:

Helloworld for automotive with S32K344!

Then wait for reception. After receiving 10 bytes of data, generate uart_callback interrupt and enter LPUART_UART_IP_ENET_END_TRANSFER. You can see that the data received in RX_Buffer is consistent with the data sent.

Then, the code will loop back the received data. The test situation is as follows:

The figure below shows two groups of tests:

PC sends: 1234567890, after MCU receives it, loop it back.

PC sends: 0987654321, after MCU receives it, debug stops at the breakpoint, you can check the received buffer situation, you can see that the buffer data is correct.

14.png

Fig 14

15.png

Fig 15

Attached are two code packages:

(1) Uart_TS_T40D34M40I0R0_miniK312_3.zipEB MCAL command line method

After unzip the code, put it in: C:\NXP\SW32K3_S32M27x_RTD_R21-11_4.0.0\eclipse\plugins, and then you can compile it directly using the command line :

16.png

Fig 16

(2)Mcal_UARTDMA_S32K312_RTD400_S32DS.zip:The way to import into S32DS, of course, it already contains the EB project:

17.png

Fig 17

 

Attachments
No ratings
Version history
Last update:
‎10-06-2024 04:02 AM
Updated by: