【National Technology N32G430】06 Comprehensive debugging, RTC, analog IIC, serial port
[Copy link]
This post was last edited by Qintianqintian0303 on 2022-10-25 10:58
Preface:
The epidemic is really annoying. All plans have been ruthlessly interrupted. The evaluation is about to end, so we have to speed up. Therefore, the real-time clock/sensor data acquisition/serial port parts are all introduced in this chapter.
Preparation:
During this period, the N32G430 adapter board was also made. I was going to use DuPont wires to connect for testing, but I found that there are several disadvantages to using DuPont wires:
One is that our EVA board is not easy to fix;
There is also the phenomenon of poor contact during movement.
So I still made an adapter board. Due to manual measurement (N32G430C8L7_STB_V1.0.pcb has no content), there are still some deviations in the actual product. It can still be installed by simply adjusting the pin angle.
The rough dimensions are as follows:
The actual picture after assembly is as follows:
There seems to be no problem with the pins at present. The program written previously can run normally, and the peripheral drivers are normal.
Next is the operation analysis of the N32G430 evaluation page:
Use the mind map to construct an overall testing system.
Specific test:
Next, we will carry out the specific test content of the remaining three parts.
1. RTC test experience
The main parts of RTC are mainly divided into machine detection, initialization, and RTC acquisition and setting.
Each time the power is turned on, the data stored in the backup register is used to determine whether the RTC is working. The backup register is powered by the battery power pin, so it will not stop working due to changes in the MCU power supply. If the backup register is reset, the RTC needs to be initialized.
The code is as follows:
void port_RTC_init(void)
{
/* Enable the PWR clock */
RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_PWR);
/* Allow access to RTC */
PWR_RTC_Backup_Access_Enable();
/* check data from bpr dt register */
if(RTC_Backup_Register_Read(RTC_BACKUP_REGISTER_1) != ERTC_BPR_DT1)
{
/* ertc configuration */
ertc_config();
/* write to ertc bpr data registers */
RTC_Backup_Register_Write(RTC_BACKUP_REGISTER_1,ERTC_BPR_DT1);
}
}
Initialization code:
/******************************************************************************/
//******************************************************************************
// 函数名称 : RTC_Date_And_Time_Default_Value
// 函数描述 : 时间参数初始值
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void RTC_Date_And_Time_Default_Value(void)
{
eRTC_set.week = 2;
eRTC_set.day = 20;
eRTC_set.month = 9;
eRTC_set.year = 22;
eRTC_set.hour = 10;
eRTC_set.min = 0;
eRTC_set.sec = 0;
}
/**
*\*\name RTC_CLKSource_Config.
*\*\fun Configure the RTC peripheral by selecting the clock source.
*\*\param ClkSrc
*\*\ - RTC_CLK_HSE128 clock source select HSE/128
*\*\ - RTC_CLK_LSE clock source select LSE
*\*\ - RTC_CLK_LSI clock source select LSI
*\*\param FirstLastCfg
*\*\ - RTC_CLK_FIRST_CONFIG
*\*\ - RTC_CLK_LAST_CONFIG
*\*\return none
**/
//******************************************************************************
// 函数名称 : RTC_CLKSource_Config
// 函数描述 : RTC时钟配置,并获取分频参数
// 输入参数 :
// ClkSrc:
// - RTC_CLK_HSE128 clock source select HSE/128
// - RTC_CLK_LSE clock source select LSE
// - RTC_CLK_LSI clock source select LSI
//param FirstLastCfg:
// - RTC_CLK_FIRST_CONFIG
// - RTC_CLK_LAST_CONFIG
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void RTC_CLKSource_Config(uint8_t ClkSrc, uint8_t FirstLastCfg)
{
/* Enable the PWR clock */
RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_PWR);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
/* Allow access to RTC */
PWR_RTC_Backup_Access_Enable();
RCC_Backup_Reset();
/* Disable RTC clock */
RCC_RTC_Clock_Disable();
if (ClkSrc == RTC_CLK_HSE128)
{
if (FirstLastCfg == RTC_CLK_FIRST_CONFIG)
{
/* Enable HSE */
RCC_LSI_Disable();
RCC_HSE_Config(RCC_HSE_ENABLE);
while (RCC_HSE_Stable_Wait() == ERROR)
{
}
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_HSE_DIV128);
}
else
{
RCC_LSI_Disable();
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_HSE_DIV128);
/* Enable HSE */
RCC_HSE_Config(RCC_HSE_ENABLE);
while (RCC_HSE_Stable_Wait() == ERROR)
{
}
}
SynchPrediv = 0x1E8; // 8M/128 = 62.5KHz
AsynchPrediv = 0x7F; // value range: 0-7F
}
else if (ClkSrc == RTC_CLK_LSE)
{
if (FirstLastCfg == RTC_CLK_FIRST_CONFIG)
{
/* Enable the LSE OSC32_IN PC14 */
RCC_LSI_Disable(); // LSI is turned off here to ensure that only one clock is turned on
#if (_LSE_BYPASS_)
RCC_LSE_Config(RCC_LSE_BYPASS, 0x141);
#else
RCC_LSE_Config(RCC_LSE_ENABLE, 0x141);
#endif
while (RCC_Flag_Status_Get(RCC_FLAG_LSERD) == RESET)
{
}
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_LSE);
}
else
{
/* Enable the LSE OSC32_IN PC14 */
RCC_LSI_Disable();
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_LSE);
#if (_LSE_BYPASS_)
RCC_LSE_Config(RCC_LSE_BYPASS, 0x141);
#else
RCC_LSE_Config(RCC_LSE_ENABLE, 0x141);
#endif
while (RCC_Flag_Status_Get(RCC_FLAG_LSERD) == RESET)
{
}
}
SynchPrediv = 0xFF; // 32.768KHz
AsynchPrediv = 0x7F; // value range: 0-7F
}
else if (ClkSrc == RTC_CLK_LSI)
{
if (FirstLastCfg == RTC_CLK_FIRST_CONFIG)
{
/* Enable the LSI OSC */
RCC_LSI_Enable();
while (RCC_Flag_Status_Get(RCC_FLAG_LSIRD) == RESET)
{
}
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_LSI);
}
else
{
RCC_RTC_Clock_Config(RCC_RTCCLK_SRC_LSI);
/* Enable the LSI OSC */
RCC_LSI_Enable();
while (RCC_Flag_Status_Get(RCC_FLAG_LSIRD) == RESET)
{
}
}
SynchPrediv = 0x13B; // 39.64928KHz
AsynchPrediv = 0x7F; // value range: 0-7F
}
else
{
}
/* Enable the RTC Clock */
RCC_RTC_Clock_Enable();
RTC_Wait_For_Synchronization();
}
/**
*\*\name RTC_Prescaler_Config.
*\*\fun RTC prescaler config.
*\*\param RTC_InitStruct: pointer to a RTC_InitType structure.
*\*\ - RTC_HourFormat
*\*\ - RTC_24HOUR_FORMAT
*\*\ - RTC_12HOUR_FORMAT
*\*\ - RTC_AsynchPrediv the value in the 0-0x7F range
*\*\ - RTC_SynchPrediv the value in the 0-0x7FFF range
*\*\return none
**/
static void RTC_Prescaler_Config(RTC_InitType *RTC_InitStruct)
{
/* Configure the RTC data register and RTC prescaler */
RTC_InitStruct->RTC_AsynchPrediv = AsynchPrediv;
RTC_InitStruct->RTC_SynchPrediv = SynchPrediv;
RTC_InitStruct->RTC_HourFormat = RTC_24HOUR_FORMAT;
}
//******************************************************************************
// 函数名称 : ertc_config
// 函数描述 : ert初始化配置
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void ertc_config(void)
{
RTC_Date_And_Time_Default_Value();
RTC_CLKSource_Config(RTC_CLK_LSE,RTC_CLK_FIRST_CONFIG);
RTC_Prescaler_Config(&RTC_InitStructure);
/* RTC calendar regulate */
Set_Time();
}
//******************************************************************************
// 函数名称 : Set_Time
// 函数描述 : 设置时间
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void Set_Time(void)
{
// Date
eDRTC_set.WeekDay = eRTC_set.week;
eDRTC_set.Date = eRTC_set.day;
eDRTC_set.Month = eRTC_set.month;
eDRTC_set.Year = eRTC_set.year;
// Time
eTRTC_set.H12 = RTC_AM_H12;
eTRTC_set.Hours = eRTC_set.hour;
eTRTC_set.Minutes = eRTC_set.min;
eTRTC_set.Seconds = eRTC_set.sec;
RTC_CLKSource_Config(RTC_CLK_LSE,RTC_CLK_FIRST_CONFIG);
RTC_Write_Protection_Disable();
RTC_Prescaler_Config(&RTC_InitStructure);
RTC_Calendar_Initializes(RTC_FORMAT_BIN,&RTC_InitStructure,&eDRTC_set,&eTRTC_set,DISABLE);
RTC_Write_Protection_Enable();
}
RTC acquisition and setting code:
//******************************************************************************
// 函数名称 : Get_Time
// 函数描述 : 获取时间
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void Get_Time(void)
{
RTC_Time_Get(RTC_FORMAT_BIN,&eTRTC);
RTC_Date_Get(RTC_FORMAT_BIN,&eDRTC);
eRTC.week = eDRTC.WeekDay;
eRTC.day = eDRTC.Date;
eRTC.month = eDRTC.Month;
eRTC.year = eDRTC.Year;
eRTC.hour = eTRTC.Hours;
eRTC.min = eTRTC.Minutes;
eRTC.sec = eTRTC.Seconds;
}
It should be noted here that normally we can write to the RTC register by removing the write protection, but N32G430 still needs to be reconfigured before it can be written normally, otherwise there will be a random number problem with the RTC. Is it possible that turning off the write protection will cause the RTC to reset?
2. IIC obtains AHT20 and SPL06 data
AHT20 is a temperature and humidity sensor, and SPL06 is a temperature and atmospheric pressure sensor. There is a slight difference in their IICs, that is, AHT20 does not need to send the register address after sending the device address, while SPL06 has more registers and needs to access specific registers.
Software IIC each stage code:
#define IIC1_RCU_GPIO_clock RCC_AHB_Peripheral_Clock_Enable(IIC1_MASTER_PERIPH_GPIO);
#define IIC1_SDA_INITOut IIC1_SDA_GPIO_OutConfig()
#define IIC1_SDA_INITIn IIC1_SDA_GPIO_InConfig()
#define IIC1_SDA_SET GPIO_Pins_Set(IIC1_MASTER_GPIO,IIC1_MASTER_SDA_PIN)
#define IIC1_SDA_RESET GPIO_Pins_Reset(IIC1_MASTER_GPIO,IIC1_MASTER_SDA_PIN)
#define IIC1_ReadSDA GPIO_Input_Pin_Data_Get(IIC1_MASTER_GPIO, IIC1_MASTER_SDA_PIN)
#define IIC1_SCL_INITOut IIC1_SCL_GPIO_OutConfig()
#define IIC1_SCL_SET GPIO_Pins_Set(IIC1_MASTER_GPIO,IIC1_MASTER_CLK_PIN)
#define IIC1_SCL_RESET GPIO_Pins_Reset(IIC1_MASTER_GPIO,IIC1_MASTER_CLK_PIN)
/*********************************全局变量**************************************/
/*********************************函数******************************************/
void IIC1_IOInit(void);
void IIC1_SDA_GPIO_OutConfig(void);
void IIC1_SDA_GPIO_InConfig(void);
void IIC1_SCL_GPIO_OutConfig(void);
void IIC1_IIC_Init(void);
void IIC1_IIC_Start(void);
void IIC1_IIC_Stop(void);
void IIC1_SendACK(uint8_t ack);
uint8_t IIC1_RecvACK(void);
uint8_t IIC1_SendByte(uint8_t dat);
uint8_t IIC1_RecvByte(void);
void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr);
void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr);
void IIC1_US_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr);
void IIC1_US_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr);
//******************************************************************************
//* 函数名称 : SPI_IOInit()
//* 函数描述 : SPI对应的IO口初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IOInit(void)
{
GPIO_InitType GPIO_InitStructure;
IIC1_RCU_GPIO_clock;
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = IIC1_MASTER_SDA_PIN|IIC1_MASTER_CLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(IIC1_MASTER_GPIO, &GPIO_InitStructure);
IIC1_SDA_SET;
IIC1_SCL_SET;
}
//******************************************************************************
//* 函数名称 : IIC1_SDA_GPIO_OutConfig()
//* 函数描述 : IIC1SDA对应的IO口设置为输出模式
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SDA_GPIO_OutConfig(void)
{
GPIO_InitType GPIO_InitStructure;
IIC1_RCU_GPIO_clock;
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = IIC1_MASTER_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(IIC1_MASTER_GPIO, &GPIO_InitStructure);
}
//******************************************************************************
//* 函数名称 : IIC1_SDA_GPIO_InConfig()
//* 函数描述 : IIC1 SDA对应的IO口设置为输入模式
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SDA_GPIO_InConfig(void)
{
GPIO_InitType GPIO_InitStructure;
IIC1_RCU_GPIO_clock;
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = IIC1_MASTER_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(IIC1_MASTER_GPIO, &GPIO_InitStructure);
}
//******************************************************************************
//* 函数名称 : IIC1_SCL_GPIO_OutConfig()
//* 函数描述 : IIC1SCL对应的IO口设置为输出模式
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SCL_GPIO_OutConfig(void)
{
GPIO_InitType GPIO_InitStructure;
IIC1_RCU_GPIO_clock;
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = IIC1_MASTER_CLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(IIC1_MASTER_GPIO, &GPIO_InitStructure);
}
//******************************************************************************
//* 函数名称 : IIC1_IIC_Init()
//* 函数描述 : IIC初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Init(void)
{
IIC1_SDA_INITOut;
// IIC1_IIC_Stop();
IIC1_SDA_RESET;
IIC1_SCL_RESET;
}
//******************************************************************************
//* 函数名称 : IIC1_IIC_Start()
//* 函数描述 : I2C1开始信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Start(void)
{
IIC1_SDA_SET;
delay_us(8);
IIC1_SCL_SET;
delay_us(14);
IIC1_SDA_RESET;
delay_us(14);
IIC1_SCL_RESET;
delay_us(14);
}
//******************************************************************************
//* 函数名称 : IIC1_IIC_Stop(void)
//* 函数描述 : IIC停止信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Stop(void)
{
IIC1_SDA_RESET;
delay_us(14);
IIC1_SCL_SET;
delay_us(8);
IIC1_SDA_SET;
delay_us(14);
}
//******************************************************************************
//* 函数名称 : IIC1_SendACK(uint8_t ack)
//* 函数描述 : 发送应答信号
//* 输入参数 :ack (0:ACK 1:NAK)
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SendACK(uint8_t ack)
{
IIC1_SDA_INITOut;
if(ack == 0)
IIC1_SDA_RESET; //写应答信号
else
IIC1_SDA_SET;
delay_us(14);
IIC1_SCL_SET; //拉高时钟线
delay_us(14); //延时
IIC1_SCL_RESET; //拉低时钟线
delay_us(14); //延时
}
//******************************************************************************
//* 函数名称 : uint8_t IIC1_RecvACK(void)
//* 函数描述 : 接收应答信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : RecvACK
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_RecvACK(void)
{
uint8_t RecvACK;
IIC1_SDA_INITIn; //SDA接口为输入
delay_us(8);
IIC1_SCL_SET; //拉高时钟线
delay_us(8); //延时
RecvACK = IIC1_ReadSDA; //读应答信号
IIC1_SCL_RESET; //拉低时钟线
delay_us(8); //延时
IIC1_SDA_INITOut;
return RecvACK;
}
//******************************************************************************
//* 函数名称 : void IIC1_SendByte(uint8_t dat)
//* 函数描述 : 向设备发送一个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_SendByte(uint8_t dat)
{
uint8_t datsendbit;
uint8_t RecvACK;
for (uint8_t i=0; i<8; i++) //8位计数器
{
datsendbit = ((dat & 0x80) >> 7);
dat <<= 1; //移出数据的最高位
if(datsendbit == 1)
{
IIC1_SDA_SET;
}
if(datsendbit == 0)
{
IIC1_SDA_RESET;
} //送数据口
delay_us(8);
IIC1_SCL_SET; //拉高时钟线
delay_us(8); //延时
IIC1_SCL_RESET; //拉低时钟线
delay_us(8);
}
RecvACK = IIC1_RecvACK();
return RecvACK;
}
//******************************************************************************
//* 函数名称 : IIC1_RecvByte()
//* 函数描述 : IIC1接收一个数据
//* 输入参数 :dat
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_RecvByte(void)
{
uint8_t RecvDat = 0;
IIC1_SDA_INITIn;
for (uint8_t i=0; i<8; i++) //8位计数器
{
RecvDat <<= 1;
IIC1_SCL_SET; //拉高时钟线
delay_us(10); //延时
RecvDat |= (IIC1_ReadSDA);
IIC1_SCL_RESET; //拉低时钟线
delay_us(10); //延时
}
IIC1_SDA_INITOut;
return RecvDat;
}
//******************************************************************************
//* 函数名称 : void IIC1_SendByte(uint8_t dat)
//* 函数描述 : IIC1向设备发送多个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
uint8_t ack = 0;
IIC1_IIC_Start();
IIC1_SendByte(dev_addr<<1);
for(uint8_t i = 0; i < len; i++)
{
ack = IIC1_SendByte(*(dat+i));
}
IIC1_IIC_Stop();
}
//******************************************************************************
//* 函数名称 : IIC1_SendBytes
//* 函数描述 : IIC1从设备接收多个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
IIC1_IIC_Start();
IIC1_SendByte((dev_addr<<1)+1);
for(uint8_t i = 0; i < len; i++)
{
*(dat+i) = IIC1_RecvByte();
if(i == (len - 1))
{
IIC1_SendACK(1);
}
else
{
IIC1_SendACK(0);
}
}
IIC1_IIC_Stop();
}
//******************************************************************************
//* 函数名称 : void IIC1_US_SendBytes(uint8_t dat)
//* 函数描述 : IIC1向设备固定开始地址连续发送数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_US_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr)
{
uint8_t ack = 0;
IIC1_IIC_Start();
IIC1_SendByte(dev_addr<<1);
IIC1_SendByte(reg_addr);
for(uint8_t i = 0; i < len; i++)
{
ack = IIC1_SendByte(*(dat+i));
}
IIC1_IIC_Stop();
}
//******************************************************************************
//* 函数名称 : IIC1_US_RecvBytes
//* 函数描述 : IIC1从设备固定地址连续接收数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_US_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr)
{
IIC1_IIC_Start();
IIC1_SendByte(dev_addr<<1);
IIC1_SendByte(reg_addr);
IIC1_IIC_Start();
IIC1_SendByte((dev_addr<<1)+1);
for(uint8_t i = 0; i < len; i++)
{
*(dat+i) = IIC1_RecvByte();
if(i == (len - 1))
{
IIC1_SendACK(1);
}
else
{
IIC1_SendACK(0);
}
}
IIC1_IIC_Stop();
}
I tested the hardware IIC and it was not completely successful. I was able to read the data but it was wrong. This is a step forward compared to reading out FF. Moreover, it is necessary to design the modes of these two sensors separately. There is no obvious advantage over the software simulation method, so I won’t dwell on it. After I finish, everyone can help point out the problem.
The hardware IIC code is as follows:
//******************************************************************************
//* 函数名称 : IIC1_IOInit
//* 函数描述 : IIC1初始化及IO口初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IOInit(void)
{
I2C_InitType i2c1_master;
GPIO_InitType i2c1_gpio;
RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_I2C1);
RCC_AHB_Peripheral_Clock_Enable(IIC1_MASTER_PERIPH_GPIO);
GPIO_Structure_Initialize(&i2c1_gpio);
/*PD13 -- SCL; PD12 -- SDA*/
i2c1_gpio.Pin = IIC1_MASTER_SDA_PIN | IIC1_MASTER_CLK_PIN;
i2c1_gpio.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;
i2c1_gpio.GPIO_Mode = GPIO_MODE_AF_OD;
i2c1_gpio.GPIO_Alternate = GPIO_AF7_I2C1;
i2c1_gpio.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(IIC1_MASTER_GPIO, &i2c1_gpio);
I2C_Reset(I2C1);
I2C_Initializes_Structure(&i2c1_master);
i2c1_master.BusMode = I2C_BUSMODE_I2C;
i2c1_master.DutyCycle = I2C_SMDUTYCYCLE_1;
i2c1_master.OwnAddr1 = 0x76;
i2c1_master.AckEnable = I2C_ACKEN;
i2c1_master.AddrMode = I2C_ADDR_MODE_7BIT;
i2c1_master.ClkSpeed = 100000; /* 100k */
I2C_Initializes(I2C1, &i2c1_master);
I2C_ON(I2C1);
}
//******************************************************************************
//* 函数名称 : IIC1_IIC_Init()
//* 函数描述 : IIC初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Init(void)
{
I2C_Generate_Stop_Enable(I2C1);
}
//******************************************************************************
//* 函数名称 : void IIC1_SendBytes(uint8_t dat)
//* 函数描述 : IIC1向设备固定开始地址连续发送数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
uint8_t* sendBufferPtr = dat;
I2CTimeout = I2CT_LONG_TIMEOUT;
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Start_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_MODE_FLAG)) /* EV5 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_7bit_Addr_Send(I2C1, dev_addr, I2C_DIRECTION_SEND);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_TXMODE_FLAG)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
// I2C_Data_Send(I2C1,reg_addr);
// I2CTimeout = I2CT_LONG_TIMEOUT;
// while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV6 */
// {
// if ((I2CTimeout--) == 0)
// {
// break;
// }
// }
/* send data */
while (len-- > 0)
{
I2C_Data_Send(I2C1, *sendBufferPtr++);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV8 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
}
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDED)) /* EV8-2 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Stop_Enable(I2C1);
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
}
//******************************************************************************
//* 函数名称 : IIC1_RecvBytes
//* 函数描述 : IIC1从设备固定地址连续接收数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
uint8_t* recvBufferPtr = dat;
I2CTimeout = I2CT_LONG_TIMEOUT;
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Acknowledg_Enable(I2C1);
/* send start */
I2C_Generate_Start_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_MODE_FLAG)) /* EV5 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
/* send addr */
I2C_7bit_Addr_Send(I2C1, dev_addr, I2C_DIRECTION_RECV);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_RXMODE_FLAG)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
// I2C_Data_Send(I2C1,reg_addr);
// I2CTimeout = I2CT_LONG_TIMEOUT;
// while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV6 */
// {
// if ((I2CTimeout--) == 0)
// {
// break;
// }
// }
if (len == 1)
{
I2C_Acknowledg_Disable(I2C1);
(void)(I2C1->STS1); /*/ clear ADDR */
(void)(I2C1->STS2);
I2C_Generate_Stop_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Flag_Status_Get(I2C1, I2C_FLAG_RXDATNE))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
}
else if (len == 2)
{
I2C1->CTRL1 |= 0x0800; /*/ set ACKPOS */
(void)(I2C1->STS1);
(void)(I2C1->STS2);
I2C_Acknowledg_Disable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Flag_Status_Get(I2C1, I2C_FLAG_BYTEF))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Stop_Enable(I2C1);
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
}
else
{
I2C_Acknowledg_Enable(I2C1);
(void)(I2C1->STS1);
(void)(I2C1->STS2);
while (len)
{
if (len == 3)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Flag_Status_Get(I2C1, I2C_FLAG_BYTEF))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Acknowledg_Disable(I2C1);
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Flag_Status_Get(I2C1, I2C_FLAG_BYTEF))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Stop_Enable(I2C1);
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
break;
}
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG)) /* EV7 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
*recvBufferPtr++ = I2C_Data_Recv(I2C1);
len--;
}
}
I2CTimeout = I2CT_LONG_TIMEOUT;
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
}
//******************************************************************************
//* 函数名称 : void IIC1_US_SendBytes(uint8_t dat)
//* 函数描述 : IIC1向设备固定开始地址连续发送数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_US_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr)
{
uint8_t* sendBufferPtr = dat;
I2CTimeout = I2CT_LONG_TIMEOUT;
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Start_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_MODE_FLAG)) /* EV5 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_7bit_Addr_Send(I2C1, dev_addr, I2C_DIRECTION_SEND);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_TXMODE_FLAG)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Data_Send(I2C1,reg_addr);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
/* send data */
while (len-- > 0)
{
I2C_Data_Send(I2C1, *sendBufferPtr++);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV8 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
}
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDED)) /* EV8-2 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_Generate_Stop_Enable(I2C1);
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
}
//******************************************************************************
//* 函数名称 : IIC1_US_RecvBytes
//* 函数描述 : IIC1从设备固定地址连续接收数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_US_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr,uint8_t reg_addr)
{
uint8_t* recvBufferPtr = dat;
I2CTimeout = I2CT_LONG_TIMEOUT;
while (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BUSY))
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_PEC_Position_Set(I2C1, I2C_PEC_POS_CURRENT);
I2C_Acknowledg_Enable(I2C1);
/* send start */
I2C_Generate_Start_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_MODE_FLAG)) /* EV5 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
/* send addr */
I2C_7bit_Addr_Send(I2C1, dev_addr, I2C_DIRECTION_SEND);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_TXMODE_FLAG)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
/** Clear EV6 by setting again the PE bit */
I2C_ON(I2C1);
/** Send the address to write to */
I2C_Data_Send(I2C1,reg_addr);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_SENDING)) /* EV6 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
/* send start */
I2C_Generate_Start_Enable(I2C1);
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_MODE_FLAG)) /* EV5 */
{
if ((I2CTimeout--) == 0)
{
break;
}
}
I2C_7bit_Addr_Send(I2C1, dev_addr, I2C_DIRECTION_RECV);
/* Test on EV6 and clear it */
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Flag_Status_Get(I2C1, I2C_FLAG_ADDRF)) //EV6
{
if ((I2CTimeout--) == 0)
break;
}
if (len == 1)
{
I2C_Acknowledg_Disable(I2C1);
(void)(I2C1->STS1); /*/ clear ADDR */
(void)(I2C1->STS2);
/** Generates START condition to close communication */
I2C_Generate_Start_Enable(I2C1);
}
else
{
(void)(I2C1->STS1); /*/ clear ADDR */
(void)(I2C1->STS2);
}
while (len)
{
if(len <= 2)
{
if(len == 1)
{
/** Wait until RXNE flag is set */
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG))
{
if ((I2CTimeout--) == 0)
break;
}
/** Read data from DAT */
*recvBufferPtr = I2C_Data_Recv(I2C1);
/** Point to the next location where the byte read will be saved */
recvBufferPtr++;
/** Decrement the read bytes counter */
len--;
/** Generates STOP condition to release SCL/SDA line */
I2C_Generate_Stop_Enable(I2C1);
}
else
{
/** Wait until RXNE flag is set */
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG))
{
if ((I2CTimeout--) == 0)
break;
}
/** Disable Acknowledgement */
I2C_Acknowledg_Disable(I2C1);
/** Read data from DAT */
*recvBufferPtr = I2C_Data_Recv(I2C1);
/** Point to the next location where the byte read will be saved */
recvBufferPtr++;
/** Decrement the read bytes counter */
len--;
/** Generates START condition to close communication */
I2C_Generate_Start_Enable(I2C1);
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG))
{
if((I2CTimeout--) == 0)
break;
}
/** Read data from DAT */
*recvBufferPtr = I2C_Data_Recv(I2C1);
/** Point to the next location where the byte read will be saved */
recvBufferPtr++;
/** Decrement the read bytes counter */
len--;
/** Generates STOP condition to release SCL/SDA line */
I2C_Generate_Stop_Enable(I2C1);
}
}
else
{
/** Test on EV7 and clear it */
I2CTimeout = I2CT_LONG_TIMEOUT;
while (!I2C_Event_Check(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG))
{
if((I2CTimeout--) == 0)
break;
}
/** Read a byte from the EEPROM */
*recvBufferPtr = I2C_Data_Recv(I2C1);
/** Point to the next location where the byte read will be saved */
recvBufferPtr++;
/** Decrement the read bytes counter */
len--;
if (I2C_Flag_Status_Get(I2C1, I2C_FLAG_BYTEF))
{
/** Read a byte from the EEPROM */
*recvBufferPtr = I2C_Data_Recv(I2C1);
/** Point to the next location where the byte read will be saved */
recvBufferPtr++;
/** Decrement the read bytes counter */
len--;
}
}
}
}
An incident occurred during the sensor data collection. The FLASH exceeded the limit. The MCU evaluated this time only had 64K of FLASH, so the full-color forum icon used seemed a bit large and had to be removed with great reluctance.
3. Serial port test
This serial port test is mainly carried out through communication with the NB-Iot module to obtain two important identification codes of the module. This time, the idle interrupt + DMA method is still used. This method is very suitable for this variable-length serial port communication process, which greatly reduces the interference of multiple serial port interrupts on system operation. Due to time reasons, no further exploration was made and the serial port communication was unsuccessful.
I found a problem here, as shown below:
In the same DMA demo, the channels corresponding to USART2's Tx are indeed different, and there is no complete correspondence in the user manual. 0x03: USART2_TX 0x04: USART2_RX is different from the expression mode in the demo, which can easily cause ambiguity. As mentioned before, the definition of each field in the driver is also incomplete, which is not very friendly to novices.
Serial port initialization code:
//******************************************************************************
//* 函数名称 : USART2_init
//* 函数描述 : 串口2的初始化
//* 输入参数 :
//* 参数描述 : 对应 引脚初始化及配置
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void USART2_init(void)
{
GPIO_InitType GPIO_InitStructure;
NVIC_InitType NVIC_InitStructure;
USART_InitType USART_InitStructure;
/* Initialize GPIO_InitStructure */
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_USART2);
GPIO_Structure_Initialize(&GPIO_InitStructure);
/* Configure USARTz Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pin = GPIO_PIN_3|GPIO_PIN_2;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF5_USART2;
GPIO_Peripheral_Initialize(GPIOA, &GPIO_InitStructure);
/* USART2 configuration---------*/
USART_InitStructure.BaudRate = 115200;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
USART_Initializes(USART2, &USART_InitStructure);
/* Enable the USARTy Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initializes(&NVIC_InitStructure);
USART2_DMA1_config();
USART_DMA_Transfer_Enable(USART2,USART_DMAREQ_RX);
/* Enable USARTz Receive and Transmit interrupts */
USART_Interrput_Enable(USART2, USART_INT_IDLEF);
USART_Enable(USART2);
}
//******************************************************************************
//* 函数名称 : USART2_DMA1_config
//* 函数描述 : 串口2 DMA接收配置
//* 输入参数 :
//* 参数描述 : 对应 引脚初始化及配置
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void USART2_DMA1_config(void)
{
DMA_InitType DMA_InitStructure;
/* DMA clock enable */
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_DMA);
/* USARTy TX DMA1 Channel (triggered by USARTy Tx event) Config */
DMA_Reset(DMA_CH4);
DMA_InitStructure.PeriphAddr = (uint32_t)&(USART2->DAT);
DMA_InitStructure.MemAddr = (uint32_t)USART2RecePackBuf;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;//外设到内存
DMA_InitStructure.BufSize = 64;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_MODE_DISABLE;//外设地址不增加
DMA_InitStructure.MemoryInc = DMA_MEM_INC_MODE_ENABLE;//内存地址递增
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_BYTE;//外设数据长度
DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_BYTE;//8位数据
DMA_InitStructure.CircularMode = DMA_CIRCULAR_MODE_DISABLE;
DMA_InitStructure.Priority = DMA_CH_PRIORITY_HIGHEST;//最高DMA通道
DMA_InitStructure.Mem2Mem = DMA_MEM2MEM_DISABLE;
DMA_Initializes(DMA_CH4, &DMA_InitStructure);
DMA_Channel_Request_Remap(DMA_CH4,DMA_REMAP_USART2_RX);
/* Enable USART RX DMA Channel */
DMA_Channel_Enable(DMA_CH4);
}
I always feel like something is missing, and there is very little information online.
After continuous positioning tests, it was found that DMA was not working properly, but the configuration was correct. One USART_DMA_Transfer_Enable(USART2,USART_DMAREQ_RX); was missing. After adding it, the idle interrupt plus DMA can receive indefinite length data. After further testing, it was determined that the Rx of the CH4 channel corresponding to the serial port 2 was correct, so the configuration corresponding to DMA_Polling was wrong.
Comprehensive video:
DSC_0167
|