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:
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.
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
Fig 3
(2)dmalogicChannel_Type_2
Fig 4
The callback registered here can also be called directly in the code.
2.2.2 Mcu module
Mcu->McuClockSettingConfig->McuClockReferencePoint->Lpuart3_clk
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:
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:
Fig 7
Fig 8
2.2.5 Uart module
There are two places to configure:
(1)uart->General
Fig 9
(2)uart->uartChannel
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:
Fig 11
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.
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.
Fig 14
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 :
Fig 16
(2)Mcal_UARTDMA_S32K312_RTD400_S32DS.zip:The way to import into S32DS, of course, it already contains the EB project:
Fig 17
PS: Add another code, it add the IDLE function, based on the RTD400,
Mcal_UARTDMA_IDLE_S32K312_RTD400_S32DS.zip
Test result is:
View full article