- /**************************************************************************//**
- * @file main.c
- * @version V3.00
- * $Revision: 15 $
- * $Date: 16/06/21 7:49p $
- * @brief Demonstrate a Master how to access Slave.
- * Needs to work with I2C_Slave sample code.
- * @note
- * Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
- *
- ******************************************************************************/
- #include <stdio.h>
- #include "NUC123.h"
- #define PLLCON_SETTING CLK_PLLCON_72MHz_HXT
- #define PLL_CLOCK 72000000
- /*---------------------------------------------------------------------------------------------------------*/
- /* Global variables */
- /*---------------------------------------------------------------------------------------------------------*/
- volatile uint8_t g_u8DeviceAddr;
- volatile uint8_t g_au8MstTxData[3];
- volatile uint8_t g_u8MstRxData;
- volatile uint8_t g_u8MstDataLen;
- volatile uint8_t g_u8MstEndFlag = 0;
- typedef void (*I2C_FUNC)(uint32_t u32Status);
- static volatile I2C_FUNC s_I2C0HandlerFn = NULL;
- /*---------------------------------------------------------------------------------------------------------*/
- /* I2C0 IRQ Handler */
- /*---------------------------------------------------------------------------------------------------------*/
- void I2C0_IRQHandler(void)
- {
- uint32_t u32Status;
- u32Status = I2C0->I2CSTATUS;
- if(I2C0->I2CTOC & I2C_I2CTOC_TIF_Msk)
- {
- /* Clear I2C0 Timeout Flag */
- I2C0->I2CTOC |= I2C_I2CTOC_TIF_Msk;
- }
- else
- {
- if(s_I2C0HandlerFn != NULL)
- s_I2C0HandlerFn(u32Status);
- }
- }
- /*---------------------------------------------------------------------------------------------------------*/
- /* I2C Rx Callback Function */
- /*---------------------------------------------------------------------------------------------------------*/
- void I2C_MasterRx(uint32_t u32Status)
- {
- if(u32Status == 0x08) /* START has been transmitted and prepare SLA+W */
- {
- I2C0->I2CDAT = g_u8DeviceAddr << 1; /* Write SLA+W to Register I2CDAT */
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x18) /* SLA+W has been transmitted and ACK has been received */
- {
- I2C0->I2CDAT = g_au8MstTxData[g_u8MstDataLen++];
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x20) /* SLA+W has been transmitted and NACK has been received */
- {
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STA_STO_SI);
- }
- else if(u32Status == 0x28) /* DATA has been transmitted and ACK has been received */
- {
- if(g_u8MstDataLen != 2)
- {
- I2C0->I2CDAT = g_au8MstTxData[g_u8MstDataLen++];
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else
- {
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STA_SI);
- }
- }
- else if(u32Status == 0x10) /* Repeat START has been transmitted and prepare SLA+R */
- {
- I2C0->I2CDAT = ((g_u8DeviceAddr << 1) | 0x01); /* Write SLA+R to Register I2CDAT */
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x40) /* SLA+R has been transmitted and ACK has been received */
- {
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x58) /* DATA has been received and NACK has been returned */
- {
- g_u8MstRxData = I2C0->I2CDAT;
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STO_SI);
- g_u8MstEndFlag = 1;
- }
- else
- {
- /* TO DO */
- printf("Status 0x%x is NOT processed\n", u32Status);
- }
- }
- /*---------------------------------------------------------------------------------------------------------*/
- /* I2C Tx Callback Function */
- /*---------------------------------------------------------------------------------------------------------*/
- void I2C_MasterTx(uint32_t u32Status)
- {
- if(u32Status == 0x08) /* START has been transmitted */
- {
- I2C0->I2CDAT = g_u8DeviceAddr << 1; /* Write SLA+W to Register I2CDAT */
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x18) /* SLA+W has been transmitted and ACK has been received */
- {
- I2C0->I2CDAT = g_au8MstTxData[g_u8MstDataLen++];
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else if(u32Status == 0x20) /* SLA+W has been transmitted and NACK has been received */
- {
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STA_STO_SI);
- }
- else if(u32Status == 0x28) /* DATA has been transmitted and ACK has been received */
- {
- if(g_u8MstDataLen != 3)
- {
- I2C0->I2CDAT = g_au8MstTxData[g_u8MstDataLen++];
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_SI);
- }
- else
- {
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STO_SI);
- g_u8MstEndFlag = 1;
- }
- }
- else
- {
- /* TO DO */
- printf("Status 0x%x is NOT processed\n", u32Status);
- }
- }
- void SYS_Init(void)
- {
- /*---------------------------------------------------------------------------------------------------------*/
- /* Init System Clock */
- /*---------------------------------------------------------------------------------------------------------*/
- /* Enable XT1_OUT (PF0) and XT1_IN (PF1) */
- SYS->GPF_MFP |= SYS_GPF_MFP_PF0_XT1_OUT | SYS_GPF_MFP_PF1_XT1_IN;
- /* Enable Internal RC 22.1184MHz clock */
- CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
- /* Waiting for Internal RC clock ready */
- while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk));
- /* Switch HCLK clock source to Internal RC and and HCLK source divide 1 */
- CLK->CLKSEL0 &= ~CLK_CLKSEL0_HCLK_S_Msk;
- CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_HIRC;
- CLK->CLKDIV &= ~CLK_CLKDIV_HCLK_N_Msk;
- CLK->CLKDIV |= CLK_CLKDIV_HCLK(1);
- /* Enable external XTAL 12MHz clock */
- CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;
- /* Waiting for external XTAL clock ready */
- while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));
- /* Set core clock as PLL_CLOCK from PLL */
- CLK->PLLCON = PLLCON_SETTING;
- while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk));
- CLK->CLKSEL0 &= (~CLK_CLKSEL0_HCLK_S_Msk);
- CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_PLL;
- /* Update System Core Clock */
- /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
- //SystemCoreClockUpdate();
- PllClock = PLL_CLOCK; // PLL
- SystemCoreClock = PLL_CLOCK / 1; // HCLK
- CyclesPerUs = PLL_CLOCK / 1000000; // For SYS_SysTickDelay()
- /* Enable UART & I2C0 module clock */
- CLK->APBCLK |= (CLK_APBCLK_UART0_EN_Msk | CLK_APBCLK_I2C0_EN_Msk);
- /* Select UART module clock source */
- CLK->CLKSEL1 &= ~CLK_CLKSEL1_UART_S_Msk;
- CLK->CLKSEL1 |= CLK_CLKSEL1_UART_S_HXT;
- /*---------------------------------------------------------------------------------------------------------*/
- /* Init I/O Multi-function */
- /*---------------------------------------------------------------------------------------------------------*/
- /* Set GPB multi-function pins for UART0 RXD and TXD */
- SYS->GPB_MFP = SYS_GPB_MFP_PB0_UART0_RXD | SYS_GPB_MFP_PB1_UART0_TXD;
- /* Set GPF multi-function pins for I2C0 SDA and SCL */
- SYS->GPF_MFP |= (SYS_GPF_MFP_PF2_I2C0_SDA | SYS_GPF_MFP_PF3_I2C0_SCL);
- SYS->ALT_MFP1 &= ~(SYS_ALT_MFP1_PF2_Msk | SYS_ALT_MFP1_PF3_Msk);
- SYS->ALT_MFP1 |= (SYS_ALT_MFP1_PF2_I2C0_SDA | SYS_ALT_MFP1_PF3_I2C0_SCL);
- }
- void UART0_Init(void)
- {
- /*---------------------------------------------------------------------------------------------------------*/
- /* Init UART */
- /*---------------------------------------------------------------------------------------------------------*/
- /* Reset UART IP */
- SYS->IPRSTC2 |= SYS_IPRSTC2_UART0_RST_Msk;
- SYS->IPRSTC2 &= ~SYS_IPRSTC2_UART0_RST_Msk;
- /* Configure UART0 and set UART0 Baudrate */
- UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HXT, 115200);
- UART0->LCR = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
- }
- void I2C0_Init(void)
- {
- uint32_t u32BusClock;
- /* Reset I2C0 */
- SYS->IPRSTC2 |= SYS_IPRSTC2_I2C0_RST_Msk;
- SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2C0_RST_Msk;
- /* Enable I2C0 Controller */
- I2C0->I2CON |= I2C_I2CON_ENS1_Msk;
- /* I2C0 bus clock 100K divider setting, I2CLK = PCLK/(100K*4)-1 */
- u32BusClock = 100000;
- I2C0->I2CLK = (uint32_t)(((SystemCoreClock * 10) / (u32BusClock * 4) + 5) / 10 - 1); /* Compute proper divider for I2C clock */
- /* Get I2C0 Bus Clock */
- printf("I2C clock %d Hz\n", (SystemCoreClock / (((I2C0->I2CLK) + 1) << 2)));
- /* Set I2C0 4 Slave Addresses */
- /* Slave Address : 0x15 */
- I2C0->I2CADDR0 = (I2C0->I2CADDR0 & ~I2C_I2CADDR_I2CADDR_Msk) | (0x15 << I2C_I2CADDR_I2CADDR_Pos);
- /* Slave Address : 0x35 */
- I2C0->I2CADDR1 = (I2C0->I2CADDR1 & ~I2C_I2CADDR_I2CADDR_Msk) | (0x35 << I2C_I2CADDR_I2CADDR_Pos);
- /* Slave Address : 0x55 */
- I2C0->I2CADDR2 = (I2C0->I2CADDR2 & ~I2C_I2CADDR_I2CADDR_Msk) | (0x55 << I2C_I2CADDR_I2CADDR_Pos);
- /* Slave Address : 0x75 */
- I2C0->I2CADDR3 = (I2C0->I2CADDR3 & ~I2C_I2CADDR_I2CADDR_Msk) | (0x75 << I2C_I2CADDR_I2CADDR_Pos);
- /* Enable I2C0 interrupt and set corresponding NVIC bit */
- I2C0->I2CON |= I2C_I2CON_EI_Msk;
- NVIC_EnableIRQ(I2C0_IRQn);
- }
- void I2C0_Close(void)
- {
- /* Disable I2C0 interrupt and clear corresponding NVIC bit */
- I2C0->I2CON &= ~I2C_I2CON_EI_Msk;
- NVIC_DisableIRQ(I2C0_IRQn);
- /* Disable I2C0 and close I2C0 clock */
- I2C0->I2CON &= ~I2C_I2CON_ENS1_Msk;
- CLK->APBCLK &= ~CLK_APBCLK_I2C0_EN_Msk;
- }
- int32_t Read_Write_SLAVE(uint8_t slvaddr)
- {
- uint32_t i;
- g_u8DeviceAddr = slvaddr;
- for(i = 0; i < 0x100; i++)
- {
- g_au8MstTxData[0] = (uint8_t)((i & 0xFF00) >> 8);
- g_au8MstTxData[1] = (uint8_t)(i & 0x00FF);
- g_au8MstTxData[2] = (uint8_t)(g_au8MstTxData[1] + 3);
- g_u8MstDataLen = 0;
- g_u8MstEndFlag = 0;
- /* I2C function to write data to slave */
- s_I2C0HandlerFn = (I2C_FUNC)I2C_MasterTx;
- /* I2C as master sends START signal */
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STA);
- /* Wait I2C Tx Finish */
- while(g_u8MstEndFlag == 0);
- g_u8MstEndFlag = 0;
- /* I2C function to read data from slave */
- s_I2C0HandlerFn = (I2C_FUNC)I2C_MasterRx;
- g_u8MstDataLen = 0;
- g_u8DeviceAddr = slvaddr;
- I2C_SET_CONTROL_REG(I2C0, I2C_I2CON_STA);
- /* Wait I2C Rx Finish */
- while(g_u8MstEndFlag == 0);
- /* Compare data */
- if(g_u8MstRxData != g_au8MstTxData[2])
- {
- printf("I2C Byte Write/Read Failed, Data 0x%x\n", g_u8MstRxData);
- return -1;
- }
- }
- printf("Master Access Slave (0x%X) Test OK\n", slvaddr);
- return 0;
- }
- /*---------------------------------------------------------------------------------------------------------*/
- /* Main Function */
- /*---------------------------------------------------------------------------------------------------------*/
- int32_t main(void)
- {
- /* Unlock protected registers */
- SYS_UnlockReg();
- /* Init System, IP clock and multi-function I/O */
- SYS_Init();
- /* Lock protected registers */
- SYS_LockReg();
- /* Init UART0 for printf */
- UART0_Init();
- /*
- This sample code sets I2C bus clock to 100kHz. Then, Master accesses Slave with Byte Write
- and Byte Read operations, and check if the read data is equal to the programmed data.
- */
- printf("\n");
- printf("+----------------------------------------------------+\n");
- printf("| I2C Driver Sample Code(Master) for access Slave |\n");
- printf("| Needs to work with I2C_Slave sample code |\n");
- printf("| I2C Master (I2C0) <---> I2C Slave(I2C0) |\n");
- printf("| !! This sample code requires two borads to test !! |\n");
- printf("+----------------------------------------------------+\n");
- printf("Configure I2C0 as a master.\n");
- printf("The I/O connection for I2C0:\n");
- printf("I2C0_SDA(PF.2), I2C0_SCL(PF.3)\n");
- /* Init I2C0 */
- I2C0_Init();
- printf("\n");
- printf("Check I2C Slave(I2C0) is running first!\n");
- printf("Press any key to continue.\n");
- getchar();
- /* Access Slave with no address mask */
- printf("\n");
- printf(" == No Mask Address ==\n");
- Read_Write_SLAVE(0x15);
- Read_Write_SLAVE(0x35);
- Read_Write_SLAVE(0x55);
- Read_Write_SLAVE(0x75);
- printf("SLAVE Address test OK.\n");
- /* Access Slave with address mask */
- printf("\n");
- printf(" == Mask Address ==\n");
- Read_Write_SLAVE(0x15 & ~0x01);
- Read_Write_SLAVE(0x35 & ~0x04);
- Read_Write_SLAVE(0x55 & ~0x01);
- Read_Write_SLAVE(0x75 & ~0x04);
- printf("SLAVE Address Mask test OK.\n");
- s_I2C0HandlerFn = NULL;
- /* Close I2C0 */
- I2C0_Close();
- while(1);
- }
|