The S32K148 MCU’s Low-Power UART (LPUART) peripheral can be used as the physical layer for Modbus RTU. Below is a concise walk-through of the minimal steps and a reference driver that receives variable-langth frames terminated by a newline character.
Physical-layer essentials
- Idle level: logic high (1)
- Start bit: logic low (0)
- Data bits: 8 (LSB first)
- Parity: even (typical for Modbus RTU)
- Stop bits: 1
- Baud rate: 115 200 bit/s in this example
Pin and clock setup
Route PTC7 (LPUART1_RX) and PTC6 (LPUART1_TX) in the Pins tool. The S32 SDK’s "expert mode" automatically enables the peripheral clock (PCC->PCCn[PCC_LPUART1_INDEX]), so no extra clock call is required.
Driver objects
static uint8_t rxBuf[200];
static uint8_t rxIdx;
static uint32_t rxLeft;
Initialisation
void LPUART1_Init(void)
{
/* SDK-generated structures */
LPUART_DRV_Init(INST_LPUART1, &lpuart1_State, &lpuart1_InitConfig0);
/* Register non-blocking receive callback */
LPUART_DRV_InstallRxCallback(INST_LPUART1, RxHandler, NULL);
/* Kick off first byte */
LPUART_DRV_ReceiveData(INST_LPUART1, rxBuf, 1);
}
Interrupt-driven callback
static void RxHandler(void *drv, uart_event_t evt, void *usr)
{
(void)drv;
(void)usr;
status_t st = LPUART_DRV_GetReceiveStatus(INST_LPUART1, &rxLeft);
if (st == STATUS_SUCCESS) /* one byte received */
{
/* Append null terminator for string handling */
rxBuf[rxIdx + 1] = 0;
/* Reset index for next frame */
rxIdx = 0;
/* Re-arm for the next byte */
LPUART_DRV_ReceiveData(INST_LPUART1, rxBuf, 1);
}
else if (evt == UART_EVENT_RX_FULL)
{
/* Buffer not yet full, keep collecting */
if (rxBuf[rxIdx] != '\n' && rxIdx < sizeof(rxBuf) - 2)
{
++rxIdx;
LPUART_DRV_SetRxBuffer(INST_LPUART1, &rxBuf[rxIdx], 1);
}
}
}
With the peripheral now streaming bytes into rxBuf, higher-level Modbus RTU logic can parse the frame once the newline delimiter is detected.