- /**************************************************************************************************
- * [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. ***/