/**************************************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url] main.c
* [url=home.php?mod=space&uid=895143]@version[/url] V1.00
* [url=home.php?mod=space&uid=247401]@brief[/url] Demonstrate LPUART receives data of variable length in power-down mode, and then
* wakes up the MCU for data processing. Implement the operating characteristics of
* M2L31 low power LPUART.
*
* SPDX-License-Identifier: Apache-2.0
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2023 Nuvoton Technology Corp. All rights reserved.
***************************************************************************************************/
#include <stdio.h>
#include "NuMicro.h"
/*------------------------------------------------------------------------------------------------*/
/* Define */
/*------------------------------------------------------------------------------------------------*/
#define LPUART_RX_LPPDMA_CH 0 /* LPPDMA channel for LPUART RX */
#define RXBUFSIZE 1024 /* Buffer size */
#define POWER_DOWN_MODE CLK_PMUCTL_PDMSEL_NPD4 /* Power-down mode */
#define LPPDMA_GET_TRANS_CNT(lppdma,u32Ch) ((uint32_t)((lppdma->LPDSCT[(u32Ch)].\
CTL&LPPDMA_DSCT_CTL_TXCNT_Msk) >> \
LPPDMA_DSCT_CTL_TXCNT_Pos)) /* Read the remaining number of transfers */
#define GPIO_P0_TO_P15 0xFFFF
/*------------------------------------------------------------------------------------------------*/
/* Global variables */
/*------------------------------------------------------------------------------------------------*/
#if (defined(__GNUC__) && !defined(__ARMCC_VERSION))
uint8_t g_u8RecData[RXBUFSIZE] __attribute__((section(".lpSram")));
#else
uint8_t g_u8RecData[RXBUFSIZE] __attribute__((section(".ARM.__at_0x28000000")));
#endif
uint32_t g_u32cnt = 0; /* Receive counter */
/*------------------------------------------------------------------------------------------------*/
/* Clear Buffer function */
/*------------------------------------------------------------------------------------------------*/
void ClearBuf(uint32_t u32Addr, uint32_t u32Length, uint8_t u8Pattern)
{
uint8_t *pu8Ptr;
uint32_t i;
pu8Ptr = (uint8_t *)u32Addr;
for (i = 0; i < u32Length; i++)
{
*pu8Ptr++ = u8Pattern;
}
}
/*------------------------------------------------------------------------------------------------*/
/* LPPDMA Interrupt Handler */
/*------------------------------------------------------------------------------------------------*/
void LPPDMA0_IRQHandler(void)
{
volatile uint32_t u32regISR;
u32regISR = LPPDMA0->INTSTS;
if ((u32regISR & LPPDMA_INTSTS_TDIF_Msk) == LPPDMA_INTSTS_TDIF_Msk) /* transfer done */
{
/* Record the number of data */
g_u32cnt = RXBUFSIZE;
printf("Warning:The received data is greater than or equal to the buffer size!!!\n");
}
/* Clear interrupt flag */
LPPDMA0->TDSTS = LPPDMA0->TDSTS;
}
/*------------------------------------------------------------------------------------------------*/
/* Init LPPDMA */
/*------------------------------------------------------------------------------------------------*/
void LPPDMA_RX_Init(void)
{
/*----------------------------------------------------------------------------------------------
LPPDMA transfer configuration:
Channel = 0
Operation mode = basic mode
Request source = LPUART0 RX(peripheral to memory)
transfer done interrupt = enable
Transfer count = RXBUFSIZE
Transfer width = 8 bits(one byte)
Source address = LPUART0->DAT
Source address increment size = 0(fixed)
Destination address = g_u8RecData
Destination address increment size = 8 bits(one byte)
Transfer type = Single transfer
Total transfer length = RXBUFSIZE * 8 bits
------------------------------------------------------------------------------------------*/
/* Open Channel 0 */
LPPDMA_Open(LPPDMA0, 1 << LPUART_RX_LPPDMA_CH);
/* Transfer count is RXBUFSIZE, transfer width is 8 bits(one byte) */
LPPDMA_SetTransferCnt(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_WIDTH_8, RXBUFSIZE);
/* Set address */
LPPDMA_SetTransferAddr(LPPDMA0,
LPUART_RX_LPPDMA_CH,
(uint32_t) & (LPUART0->DAT), /* Source address */
LPPDMA_SAR_FIX, /* Source address fixed */
(uint32_t)g_u8RecData, /* Destination address */
LPPDMA_DAR_INC); /* Destination address incremented, size = 1byte */
/* Request source is LPUART0 RX to memory */
LPPDMA_SetTransferMode(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_LPUART0_RX, FALSE, 0);
/* Transfer type is Single transfer */
LPPDMA_SetBurstType(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_REQ_SINGLE, 1);
/* Enable transfer done interrupt */
LPPDMA_EnableInt(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_INT_TRANS_DONE);
/* Enable LPPDMA0 IRQ */
NVIC_EnableIRQ(LPPDMA0_IRQn);
}
/*------------------------------------------------------------------------------------------------*/
/* LPUART0 interrupt Handler */
/*------------------------------------------------------------------------------------------------*/
void LPUART0_IRQHandler(void)
{
if (LPUART_GET_INT_FLAG(LPUART0, LPUART_INTSTS_HWTOINT_Msk))
{
/* Record the number of data */
g_u32cnt = RXBUFSIZE - LPPDMA_GET_TRANS_CNT(LPPDMA0, LPUART_RX_LPPDMA_CH) - 1;
}
/* Clear interrupt flag */
LPUART0->INTSTS = LPUART0->INTSTS;
}
/*------------------------------------------------------------------------------------------------*/
/* Init LPUART0 */
/*------------------------------------------------------------------------------------------------*/
void LPUART0_Init(void)
{
/* Reset Low Power UART0 */
SYS_ResetModule(LPUART0_RST);
/* Configure Low Power UART0 and set Low Power UART0 Baudrate */
LPUART_Open(LPUART0, 9600);
// /* Open this statement. If you want to keep LPUART clock at power-down mode NPD3/NDP4.
// To ensure accuracy, if the baud rate is set to 115200, it needs to be opened
// */
// LPSCC->CLKKEEP0 |= LPSCC_CLKKEEP0_LPUART0KEEP_Msk;
/* Set Automatic Operation Enable */
LPUART0->AUTOCTL |= LPUART_AUTOCTL_AOEN_Msk;
/* Enable LPUART PDMA RX */
LPUART0->INTEN |= LPUART_INTEN_RXPDMAEN_Msk;
/* Enable bus idle time-out(Mode 1) and set time-out counter */
LPUART0->TOUT = 255 | LPUART_TOUT_BITOMEN_Msk;
/* Enable time-out counter */
LPUART0->INTEN |= LPUART_INTEN_TOCNTEN_Msk;
/* Enable Bus Idle Time-out Wake-up */
LPUART0->AUTOCTL |= LPUART_AUTOCTL_WKAOTOEN_Msk;
/* Enable RX Time-out interrupt */
LPUART_EnableInt(LPUART0, LPUART_INTEN_RXTOIEN_Msk);
/* Enable LPUART0 IRQ */
NVIC_EnableIRQ(LPUART0_IRQn);
}
/*------------------------------------------------------------------------------------------------*/
/* Stop LPPDMA and LPUART bus idle timeout count */
/*------------------------------------------------------------------------------------------------*/
void Transfer_Stop(void)
{
/* Disable LPUART PDMA RX and time-out counter */
LPUART0->INTEN &= ~(LPUART_INTEN_RXPDMAEN_Msk | LPUART_INTEN_TOCNTEN_Msk);
/* Stop LPPDMA */
LPPDMA0->LPDSCT[1].CTL &= ~LPPDMA_DSCT_CTL_OPMODE_Msk;
}
/*------------------------------------------------------------------------------------------------*/
/* Restart LPPDMA and LPUART */
/*------------------------------------------------------------------------------------------------*/
void Transfer_Recfg(void)
{
ClearBuf((uint32_t)g_u8RecData, RXBUFSIZE, 0xFF);
g_u32cnt = 0;
/* Restart LPPDMA channel */
/* Transfer count is RXBUFSIZE, transfer width is 8 bits(one byte) */
LPPDMA_SetTransferCnt(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_WIDTH_8, RXBUFSIZE);
/* Request source is LPUART RX to memory */
LPPDMA_SetTransferMode(LPPDMA0, LPUART_RX_LPPDMA_CH, LPPDMA_LPUART0_RX, FALSE, 0);
/* Restart LPUART */
LPUART0_Init();
}
/*------------------------------------------------------------------------------------------------*/
/* Init GPIO */
/*------------------------------------------------------------------------------------------------*/
void GPIO_Init(void)
{
/* Enable GPIO clock */
CLK_EnableModuleClock(GPA_MODULE);
CLK_EnableModuleClock(GPB_MODULE);
CLK_EnableModuleClock(GPC_MODULE);
CLK_EnableModuleClock(GPD_MODULE);
CLK_EnableModuleClock(GPE_MODULE);
CLK_EnableModuleClock(GPF_MODULE);
CLK_EnableModuleClock(GPG_MODULE);
CLK_EnableModuleClock(GPH_MODULE);
/* Configure all GPIO mode*/
GPIO_SetMode(PA, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PB, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PC, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PD, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PE, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PF, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PG, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
GPIO_SetMode(PH, GPIO_P0_TO_P15, GPIO_MODE_OUTPUT);
/* Set all GPIO output high, except for special function pins*/
PA->DOUT = 0xEFFF; /* USB_VBUSP need output low, otherwise LDO will be backfilled */
PB->DOUT = 0x7FFF; /* PB15_VBUS_SEN need output low, otherwise there will be leakage*/
PC->DOUT = 0xFFF0; /* PC0~3 is CCDB, basically 1M ohm register always being */
PD->DOUT = 0xFFFF;
PE->DOUT = 0xFFFF;
PF->DOUT = 0xFFFF;
PG->DOUT = 0xFFFF;
PH->DOUT = 0xFFFF;
/* Disable GPIO clock */
CLK_DisableModuleClock(GPA_MODULE);
CLK_DisableModuleClock(GPB_MODULE);
CLK_DisableModuleClock(GPC_MODULE);
CLK_DisableModuleClock(GPD_MODULE);
CLK_DisableModuleClock(GPE_MODULE);
CLK_DisableModuleClock(GPF_MODULE);
CLK_DisableModuleClock(GPG_MODULE);
CLK_DisableModuleClock(GPH_MODULE);
}
/*------------------------------------------------------------------------------------------------*/
/* Enter NPD4 mode */
/*------------------------------------------------------------------------------------------------*/
void PowerDown_Enter(void)
{
/* Set Power-down mode */
SYS_UnlockReg();
/* Set SRAM retention range. */
CLK->PMUCTL &= ~(CLK_PMUCTL_SRETSEL_Msk);
/* 8K SRAM retention when chip enter NPD3/SPDx mode. */
CLK->PMUCTL |= (CLK_SPDSRETSEL_8K);
/* Select Power-down mode */
CLK_SetPowerDownMode(POWER_DOWN_MODE);
/* BOD must be disabled */
SYS_DISABLE_BOD();
/* Disable Power-on Reset */
SYS_DISABLE_POR();
/* Clear all wakeup flag */
CLK->PMUSTS |= CLK_PMUSTS_CLRWK_Msk;
/* Clear LPPDMA channel transfer done flag */
LPPDMA0->TDSTS = LPPDMA0->TDSTS;
/* Clear LPUART interrupt flag */
LPUART0->INTSTS = LPUART0->INTSTS;
printf("System enter to Power-down mode NPD%d.\n", (int)(CLK->PMUCTL & CLK_PMUCTL_PDMSEL_Msk));
/* Check if all the debug messages are finished */
UART_WAIT_TX_EMPTY(UART0);
/* Enter Power-down mode */
CLK_PowerDown();
}
/*------------------------------------------------------------------------------------------------*/
/* Init clock and pins */
/*------------------------------------------------------------------------------------------------*/
void SYS_Init(void)
{
/* Unlock protected registers */
SYS_UnlockReg();
/* Enable External XTAL (4~24 MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
/* Switch HCLK clock source to HIRC */
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLK0SEL_Msk) | CLK_CLKSEL0_HCLKSEL_HIRC48M ;
/* Switch HCLK1 clock source to MIRC */
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLK1SEL_Msk) | CLK_CLKSEL0_HCLK1SEL_MIRC ;
/* Select UART0 clock source is HIRC and UART module clock divider as 1 */
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL4_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
/* Select LPUART0 clock source is MIRC and LPUART module clock divider as 1*/
CLK_SetModuleClock(LPUART0_MODULE, LPSCC_CLKSEL0_LPUART0SEL_MIRC, LPSCC_CLKDIV0_LPUART0(1));
/* Enable UART0 peripheral clock */
CLK_EnableModuleClock(UART0_MODULE);
/* Enable LPUART0 peripheral clock */
CLK_EnableModuleClock(LPUART0_MODULE);
/* Enable LPSRAM clock */
CLK_EnableModuleClock(LPSRAM_MODULE);
/* LPPDMA Clock Enable */
CLK_EnableModuleClock(LPPDMA0_MODULE);
/* Set GPIO mode for unused pins */
GPIO_Init();
/* Set GPB multi-function pins for UART0 RXD and TXD */
Uart0DefaultMPF();
/* Set PA multi-function pins for LPUART0 TXD and RXD */
SYS->GPA_MFP0 = (SYS->GPA_MFP0 & ~(SYS_GPA_MFP0_PA0MFP_Msk | SYS_GPA_MFP0_PA1MFP_Msk)) | \
(SYS_GPA_MFP0_PA0MFP_LPUART0_RXD | SYS_GPA_MFP0_PA1MFP_LPUART0_TXD);
/* Lock protected registers */
SYS_LockReg();
}
/*------------------------------------------------------------------------------------------------*/
/* Init PUART0 */
/*------------------------------------------------------------------------------------------------*/
void UART_Init()
{
/* Reset UART0 */
SYS_ResetModule(UART0_RST);
/* Configure UART0 and set UART0 baud rate */
UART_Open(UART0, 115200);
}
int main(void)
{
uint32_t i, count = 0;
/* Init System, peripheral clock and multi-function I/O */
SYS_Init();
/* Init UART0 for printf */
UART_Init();
/*--------------------------------------------------------------------------------------------*/
/* LPUART Receives Variable Length Data in Power-down Mode Test */
/* 1. LPUART uses LPPDMA Channel-0 to transfer RX data to g_u8RecData */
/* 2. LPUART RX pin (PA.0) is connected to UART Tool */
/* 3. System enters power-down mode and UART RX receives data in power-down mode */
/* 4. When RX transfer done or timed out and wake-up system */
/* 5. Print the received data through uart0 */
/* 6. Repeat steps 3~5 */
/*--------------------------------------------------------------------------------------------*/
printf("+-------------------------------------------------------------------------------+\n");
printf("| M2L31 LPUART receive under Power-Down mode Sample Code |\n");
printf("+-------------------------------------------------------------------------------+\n\n");
printf(" >> Please connect PA.0 to PC by UART tool. << \n");
printf(" Press any key to start test\n\n");
getchar();
/* Clear buffer */
ClearBuf((uint32_t)g_u8RecData, RXBUFSIZE, 0xFF);
/* LPPDMA CH-0 basic Mode RX to receive data */
LPPDMA_RX_Init();
/* Init LPUART0 as Auto-operation Mode for test */
LPUART0_Init();
while (1)
{
/* Reconfigure transmission */
Transfer_Recfg();
count++;
/* Enter power down mode */
PowerDown_Enter();
printf("\nWakeup %d\n", count);
/* Wait for the number of data to be recorded */
while (g_u32cnt == 0);
Transfer_Stop();
/* Add data processing code */
printf("Received Data(%d):\n", g_u32cnt);
for (i = 0; i < g_u32cnt; i++)
printf("%c", g_u8RecData[i]);
printf("\n\n");
}
}
/*** (C) COPYRIGHT 2023 Nuvoton Technology Corp. ***/