简介
MM32L0130系列MCU是灵动微电子新推出的低功耗产品,内核使用32位的高性能Arm® Cortex-M0+ 微控制器,最高工作频率可达到48MHz,内置高速存储器,丰富的增强型 I/O 端口和多种外设。可适用于空调遥控器、温控器、耳/额温枪、便携医疗设备、气/水/电等仪表、小家电等应用领域。
MM32L0130系列MCU主要特性
u 内核与系统
Ø 32-bit Arm® Cortex®-M0+
Ø 工作频率可达48MHz
u 存储器
Ø 多达 64KB 的 Flash 存储器
Ø 多达 8KB SRAM
Ø Boot loader 支持片内 Flash 在线系统编程(ISP)
u 时钟、复位和电源管理
Ø 1.8V ∼ 5.5V 供电
Ø 上电/断电复位(POR/PDR) 、可编程电压监测器(PVD)
Ø 外部 4 ∼ 24MHz 高速晶体振荡器
Ø 外部 32.768KHz 低速振荡器(带 LSE Bypass 功能)
Ø 内置经出厂调校的8MHz 高速 RC 振荡器,全温度范围内偏差不超过 ±2.5%
Ø PLL 支持 CPU 最高运行在 48MHz,支持多种分频模式
Ø 内置 16.384KHz 低速振荡器,全温度范围内频率偏差不超过 ±3.5%
u 低功耗
Ø 多种低功耗模式,包括:低功耗运行(Low Power Run)、睡眠(Sleep)、低功耗睡眠(Low Power Sleep)、停机(Stop)、深度停机(Deep Stop)、 待机(Standby)和关机(Shutdown)模式
u 1 个 5 通道 DMA 控制器,支持外设类型包括定时器、ADC、UART、LPUART、I2C、SPI 和SLCD
u 9 个定时器
Ø 2 个 16 位通用定时器(TIM3 /TIM4),有多达 4 个输入捕获/输出比较通道,可用于IR 控制解码
Ø 2 个 16 位基本定时器(TIM16/ TIM17),有 1 个输入捕获/输出比较通道,1 组互补输出, 支持死区生成,紧急停止, 调制器门电路用于 IR 控制
Ø 1 个低功耗定时器(LPTIM),可在除待机和关机模式外的所有模式唤醒 CPU
Ø 2 个看门狗定时器(独立型的 IWDG 和窗口型的 WWDG)
Ø 1 个 RTC 计数器,支持日历功能
Ø 1 个 Systick 定时器: 24 位自减型计数器
u 多达 57 个快速 I/O 端口:
Ø 所有 I/O 口可以映像到 16 个外部中断
Ø 所有端口均可输入输出电压不高于VDD 的信号
u 多达 6 个通信接口
Ø 2 个 UART 接口
Ø 1 个低功耗 UART 接口(LPUART)
Ø 1 个 I2C 接口
Ø 2 个 SPI 接口(2 个I2S 接口)
u 1 个红外信号调制模块(Infra-Red Modulator, IRM),支持 ASK/PSK/FSK 调制
u 1 个段码式液晶驱动模块(SLCD),可驱动 40x4 或 36x8 个段码
u 1 个 12 位模数转换器(ADC),1us 转换时间,多达 15 个外部输入通道,1个内部输入通道
Ø 转换范围:0 ∼ VDDA
Ø 支持采样时间和分辨率配置
Ø 片上温度传感器
Ø 片上电压传感器
u 1 个比较器
u CRC 计算单元,8/16/32 位多项式可配置
u 96 位芯片唯一 ID(UID)
u 调试模式
Ø 串行调试接口(SWD) 接口
u 采用 LQFP64 和 LQFP48 封装
准备开发环境
1、EVB-L0130开发板
2、J-LINK调试下载器
3、USB转TLL工具
4、音箱、USB数据线
EVB-L0130属于MM32EVBoard系列开发板,板载芯片为MM32L0136C7P,带有丰富的外设资源:支持高达 4KV EFT 抗干扰能力、支持 SWD 下载调试接口、4个用户按键、1个复位按键、4个用户LED、2路UART 连接器、1个给开发板供电USB 连接器、1个8Mbit 的 SPI Flash 存储器、1个2048bit 的 I2C 存储器、4个功能选择开关(I2S或是LCD)、1个3.5mm 耳机插座,用于 I2SL/R 音频输出、1个无源扬声器、3路模拟输入电位器、1个板载段码 LCD显示屏……
准备相关资料
MM32L0130数据手册: DS_MM32L0130_SC.pdf (2.36 MB)
MM32L0130用户手册: UM_MM32L0130_SC.pdf (12.53 MB)
MM32L0130 KEIL芯片支持包: MindMotion.MM32L0130_DFP.0.0.2.pack.zip (36.45 KB)
EVB-L0130开发析用户手册: UG_EVB-L0136_SC.pdf (1.17 MB)
EVB-L0130开发板原理图: EVB-L0136_SCH.pdf (575.08 KB)
MM32L0130 MindSDK驱动程序: Windows mdk_evb-l0130 2022-08-15 1033.zip (9.04 MB)
MM32L0130 LibSample驱动程序: MM32L0130_LibSamples_V020.zip (4.19 MB)
段码LCD显示屏手册: GDC0689TP-11.pdf (896.84 KB)
#if ENABLE_ADC
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MultiTimer ADC_MultiTimer;
/* Private variables ---------------------------------------------------------*/
float RV1_Voltage = 0.0;
float RV2_Voltage = 0.0;
float RV3_Voltage = 0.0;
/* Private variables ---------------------------------------------------------*/
uint16_t ADC_Flag = 0;
uint16_t ADC_Buffer[30];
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url]
* @param
* @retval
* [url=home.php?mod=space&uid=93590]@Attention[/url]
*******************************************************************************/
void ADC_MultiTimerCallback(MultiTimer *timer, void *userData)
{
uint32_t ADC0_Value = 0;
uint32_t ADC1_Value = 0;
uint32_t ADC2_Value = 0;
if(ADC_Flag == 1)
{
ADC_Flag = 0;
for(uint8_t i = 0; i < 30;)
{
ADC0_Value += ADC_Buffer[i++];
ADC1_Value += ADC_Buffer[i++];
ADC2_Value += ADC_Buffer[i++];
}
RV1_Voltage = ((float)(ADC0_Value) / 4096.0) * 3.3 / 10.0;
RV2_Voltage = ((float)(ADC1_Value) / 4096.0) * 3.3 / 10.0;
RV3_Voltage = ((float)(ADC2_Value) / 4096.0) * 3.3 / 10.0;
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
MultiTimerStart(&ADC_MultiTimer, 250, ADC_MultiTimerCallback, "ADC");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void mADC_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel1);
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&ADC_Buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 30;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
if(DMA_InitStruct.DMA_PeripheralBaseAddr == ((uint32_t)(&ADC1->DR)))
{
DMA_SetChannelMuxSource(DMA1_Channel1, DMA1_MUX_ADC1);
if(DMA_GetChannelMuxSource(DMA1_Channel1) != DMA1_MUX_ADC1)
{
while(1);
}
}
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1, ENABLE);
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_PRESCARE = ADC_PCLK2_PRESCARE_16;
ADC_InitStructure.ADC_Mode = ADC_Mode_Continue;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC1_ExternalTrigConv_T3_CC3;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 0, ADC_Samctl_240_5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_Samctl_240_5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_Samctl_240_5);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
MultiTimerStart(&ADC_MultiTimer, 250, ADC_MultiTimerCallback, "ADC");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void DMA1_Channel1_IRQHandler(void)
{
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
DMA_ClearITPendingBit(DMA1_IT_TC1);
ADC_Flag = 1;
}
#endif
#if ENABLE_BUZZER
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MultiTimer BUZZER_MultiTimer;
/* Private variables ---------------------------------------------------------*/
BUZZER_TypeDef BUZZER_TAB[] =
{
{50, 100, 1},
{50, 100, 1},
{50, 100, 0},
};
/* Private variables ---------------------------------------------------------*/
volatile uint8_t BUZZER_Flag = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
#if 1
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void BUZZER_MultiTimerCallback(MultiTimer *timer, void *userData)
{
static uint8_t State = 0, Index = 0;
if(State == 0)
{
State = 1; BUZZER_Flag = 1;
MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index].PlayMS, BUZZER_MultiTimerCallback, "BUZZER");
}
else
{
State = 0; BUZZER_Flag = 0;
if(BUZZER_TAB[Index].KeepOn)
{
MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index++].WaitMS, BUZZER_MultiTimerCallback, "BUZZER");
}
else
{
Index = 0;
}
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void BUZZER_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM16_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM16, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (RCC_Clocks.SYSCLK_Frequency / 1000000 - 1);
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_Period = (500 - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM16, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM16, ENABLE);
MultiTimerStart(&BUZZER_MultiTimer, 100, BUZZER_MultiTimerCallback, "BUZZER");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void TIM16_IRQHandler(void)
{
static BitAction Value = Bit_RESET;
if(TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET)
{
if(BUZZER_Flag == 1)
{
if(Value == Bit_RESET) Value = Bit_SET;
else Value = Bit_RESET;
GPIO_WriteBit(GPIOA, GPIO_Pin_6, Value);
}
TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
}
}
#else
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void BUZZER_MultiTimerCallback(MultiTimer *timer, void *userData)
{
static uint8_t State = 0, Index = 0;
if(State == 0)
{
State = 1; TIM_SetCompare1(TIM3, 500);
MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index].PlayMS, BUZZER_MultiTimerCallback, "BUZZER");
}
else
{
State = 0; TIM_SetCompare1(TIM3, 0);
if(BUZZER_TAB[Index].KeepOn)
{
MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index++].WaitMS, BUZZER_MultiTimerCallback, "BUZZER");
}
else
{
Index = 0;
}
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void BUZZER_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_1);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM3, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (RCC_Clocks.PCLK1_Frequency / 1000000 - 1);
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_Period = (1000 - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
TIM_CtrlPWMOutputs(TIM3, ENABLE);
MultiTimerStart(&BUZZER_MultiTimer, 100, BUZZER_MultiTimerCallback, "BUZZER");
}
#endif
#endif
#if ENABLE_EEPROM
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void I2C_GetBuffer(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
uint8_t Flag = 0, Count = 0;
I2C_SendData(I2C1, Address);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
for(uint8_t i = 0; i < Length; i++)
{
while(1)
{
if((I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFNF)) && (Flag == 0))
{
I2C_ReadCmd(I2C1); Count++;
if(Count == Length) Flag = 1;
}
if(I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_RFNE))
{
Buffer[i] = I2C_ReceiveData(I2C1); break;
}
}
}
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void I2C_PutBuffer(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
I2C_SendData(I2C1, Address);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
for(uint8_t i = 0; i < Length; i++)
{
I2C_SendData(I2C1, *Buffer++);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
}
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_ReadData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
I2C_GetBuffer(Address, Buffer, Length);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_WriteData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
uint8_t Start, StartCount, PageNumber, FinalCount;
if((Address % EEPROM_PAGE_SIZE) == 0)
{
StartCount = 0;
PageNumber = Length / EEPROM_PAGE_SIZE;
FinalCount = Length % EEPROM_PAGE_SIZE;
}
else
{
Start = Address % EEPROM_PAGE_SIZE;
if(((Start + Length) / EEPROM_PAGE_SIZE) == 0)
{
StartCount = Length;
PageNumber = 0;
FinalCount = 0;
}
else
{
StartCount = EEPROM_PAGE_SIZE - Start;
PageNumber = (Length - StartCount) / EEPROM_PAGE_SIZE;
FinalCount = (Length - StartCount) % EEPROM_PAGE_SIZE;
}
}
if(StartCount)
{
I2C_PutBuffer(Address, Buffer, StartCount);
Address += StartCount;
Buffer += StartCount;
printf("\r\nWait A Moument..."); SysTick_DelayMS(10);
}
while(PageNumber--)
{
I2C_PutBuffer(Address, Buffer, EEPROM_PAGE_SIZE);
Address += EEPROM_PAGE_SIZE;
Buffer += EEPROM_PAGE_SIZE;
printf("\r\nWait A Moument..."); SysTick_DelayMS(10);
}
if(FinalCount)
{
I2C_PutBuffer(Address, Buffer, FinalCount);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C1, ENABLE);
I2C_StructInit(&I2C_InitStructure);
I2C_InitStructure.I2C_Mode = I2C_Mode_MASTER;
I2C_InitStructure.I2C_OwnAddress = 0;
I2C_InitStructure.I2C_Speed = I2C_Speed_STANDARD;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDRESS, I2C_Direction_Transmitter);
I2C_Cmd(I2C1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_3);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_Demo(void)
{
uint8_t rBuffer[20], wBuffer[20];
uint8_t Address = 0;
uint8_t Length = 20;
for(uint8_t i = 0; i < Length; i++)
{
rBuffer[i] = 0;
wBuffer[i] = i;
}
printf("\r\n\r\nEEPROM Write Data : ");
EEPROM_WriteData(Address, wBuffer, Length);
printf("OK"); SysTick_DelayMS(10);
printf("\r\n\r\nEEPROM Read Data : \r\n");
EEPROM_ReadData(Address, rBuffer, Length);
for(uint8_t i = 0; i < Length; i++)
{
printf("0x%02x ", rBuffer[i]);
if(((i + 1) % 10) == 0) printf("\r\n");
}
printf("\r\n\r\n");
}
#endif
/* Includes ------------------------------------------------------------------*/
#include <sfud.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SFUD_DEMO_BUFFER_SIZE (512)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t sfud_demo_buf[SFUD_DEMO_BUFFER_SIZE];
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief SFUD demo for the first flash device test
* @param addr flash start address
* @param size test flash size
* @param size test flash data buffer
* @retval
* @attention
*******************************************************************************/
void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{
sfud_err result = SFUD_SUCCESS;
const sfud_flash *flash = sfud_get_device_table() + 0;
size_t i;
/* prepare write data */
for(i = 0; i < size; i++)
{
data[i] = i;
}
/* erase test */
result = sfud_erase(flash, addr, size);
if(result == SFUD_SUCCESS)
{
printf("\r\nErase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
}
else
{
printf("\r\nErase the %s flash data failed.\r\n", flash->name);
return;
}
/* write test */
result = sfud_write(flash, addr, size, data);
if(result == SFUD_SUCCESS)
{
printf("\r\nWrite the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
}
else
{
printf("\r\nWrite the %s flash data failed.\r\n", flash->name);
return;
}
/* read test */
result = sfud_read(flash, addr, size, data);
if(result == SFUD_SUCCESS)
{
printf("\r\nRead the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr, size);
printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");
for(i = 0; i < size; i++)
{
if((i % 16) == 0)
{
printf("[%08X] ", addr + i);
}
printf("%02X ", data[i]);
if(((i + 1) % 16 == 0) || (i == size - 1))
{
printf("\r\n");
}
}
printf("\r\n");
}
else
{
printf("\r\nRead the %s flash data failed.\r\n", flash->name);
}
/* data check */
for(i = 0; i < size; i++)
{
if(data[i] != i % 256)
{
printf("\r\nRead and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
break;
}
}
if(i == size)
{
printf("\r\nThe %s flash test is success.\r\n", flash->name);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void SPI_FLASH_Init(void)
{
printf("\r\n");
if(sfud_init() == SFUD_SUCCESS)
{
sfud_demo(0, sizeof(sfud_demo_buf), sfud_demo_buf);
}
}
#if ENABLE_RTC
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MultiTimer RTC_MultiTimer;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)
{
int w, c, y;
/* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */
if((Month == 1) || (Month == 2))
{
Month += 12;
Year -= 1;
}
w = 0; /* Weekday */
c = Year / 100; /* Century */
y = Year % 100; /* Year */
w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;
while(w < 0) w += 7;
w %= 7;
return w;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_LoadDefault(RTCCAL_DateTypeDef *RTCCAL_Date, RTCCAL_TimeTypeDef *RTCCAL_Time)
{
char date[20], time[20];
char text[6][5];
uint8_t index = 0, month = 0;
memset(date, 0, sizeof(date));
memset(time, 0, sizeof(time));
memset(text, 0, sizeof(text));
memcpy(date, __DATE__, sizeof(__DATE__));
memcpy(time, __TIME__, sizeof(__TIME__));
char *str;
str = strtok(date, " ");
while(str != NULL)
{
memcpy(text[index], str, strlen(str));
index++;
str = strtok(NULL, " ");
}
str = strtok(time, ":");
while(str != NULL)
{
memcpy(text[index], str, strlen(str));
index++;
str = strtok(NULL, ":");
}
#if 0
for(uint8_t i = 0; i < index; i++)
{
printf("\r\n->%s", text[i]);
}
#endif
char *strMonth[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
for(uint8_t i = 0; i < 12; i++)
{
if(strcmp(text[0], strMonth[i]) == 0)
{
month = i + 1;
}
}
RTCCAL_Date->RTCCAL_Date = atoi(text[1]);
RTCCAL_Date->RTCCAL_Month = month;
RTCCAL_Date->RTCCAL_Year = atoi(text[2]) - 2000;
RTCCAL_Date->RTCCAL_WeekDay = RTC_GetWeek(RTCCAL_Date->RTCCAL_Year + 2000,
RTCCAL_Date->RTCCAL_Month,
RTCCAL_Date->RTCCAL_Date);
RTCCAL_Time->RTCCAL_Hours = atoi(text[3]);
RTCCAL_Time->RTCCAL_Minutes = atoi(text[4]);
RTCCAL_Time->RTCCAL_Seconds = atoi(text[5]);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_MultiTimerCallback(MultiTimer *timer, void *userData)
{
RTCCAL_TimeTypeDef RTCCAL_TimeStructure;
RTCCAL_DateTypeDef RTCCAL_DateStructure;
RTCCAL_GetTime(RTCCAL_Format_BIN, &RTCCAL_TimeStructure);
RTCCAL_GetDate(RTCCAL_Format_BIN, &RTCCAL_DateStructure);
#if ENABLE_LCD
LCD_DisplayNumber2(0, '0' + (RTCCAL_TimeStructure.RTCCAL_Hours / 10), 0);
LCD_DisplayNumber2(1, '0' + (RTCCAL_TimeStructure.RTCCAL_Hours % 10), 0);
LCD_DisplayNumber2(2, '0' + (RTCCAL_TimeStructure.RTCCAL_Minutes / 10), 0);
LCD_DisplayNumber2(3, '0' + (RTCCAL_TimeStructure.RTCCAL_Minutes % 10), 0);
LCD_DisplayNumber2(4, '0' + (RTCCAL_TimeStructure.RTCCAL_Seconds / 10), 0);
LCD_DisplayNumber2(5, '0' + (RTCCAL_TimeStructure.RTCCAL_Seconds % 10), 0);
#else
printf("\r\n%04d-%02d-%02d", RTCCAL_DateStructure.RTCCAL_Year + 2000, RTCCAL_DateStructure.RTCCAL_Month, RTCCAL_DateStructure.RTCCAL_Date);
switch(RTCCAL_DateStructure.RTCCAL_WeekDay)
{
case 0 : printf(" SUN "); break;
case 1 : printf(" MON "); break;
case 2 : printf(" TUE "); break;
case 3 : printf(" WED "); break;
case 4 : printf(" THU "); break;
case 5 : printf(" FRI "); break;
case 6 : printf(" SAT "); break;
default: break;
}
printf("%02d:%02d:%02d\r\n", RTCCAL_TimeStructure.RTCCAL_Hours, RTCCAL_TimeStructure.RTCCAL_Minutes, RTCCAL_TimeStructure.RTCCAL_Seconds);
#endif
MultiTimerStart(&RTC_MultiTimer, 500, RTC_MultiTimerCallback, "RTC");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_Init(void)
{
RTCCAL_InitTypeDef RTCCAL_InitStructure;
RTCCAL_TimeTypeDef RTCCAL_TimeStructure;
RTCCAL_DateTypeDef RTCCAL_DateStructure;
RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1ENR_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_APB1PeriphClockCmd(RCC_APB1ENR_RTC, ENABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTCCAL_EnterInitMode();
RTCCAL_WaitForSynchro();
RTCCAL_StructInit(&RTCCAL_InitStructure);
RTCCAL_InitStructure.RTCCAL_HourFormat = RTCCAL_HourFormat_24;
RTCCAL_InitStructure.RTCCAL_AsynchPrediv = 0x7F;
RTCCAL_InitStructure.RTCCAL_SynchPrediv = 0xFF;
RTCCAL_Init(&RTCCAL_InitStructure);
RTC_LoadDefault(&RTCCAL_DateStructure, &RTCCAL_TimeStructure);
RTCCAL_TimeStructure.RTCCAL_H12 = RTCCAL_H12_AM;
RTCCAL_SetTime(RTCCAL_Format_BIN, &RTCCAL_TimeStructure);
RTCCAL_SetDate(RTCCAL_Format_BIN, &RTCCAL_DateStructure);
RTCCAL_WaitForSynchro();
RTCCAL_ExitInitMode();
MultiTimerStart(&RTC_MultiTimer, 500, RTC_MultiTimerCallback, "RTC");
}
#endif
#if ENABLE_I2S
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MultiTimer I2S_MultiTimer;
/* Private variables ---------------------------------------------------------*/
uint8_t WAV_DataBuffer[2][WAV_BUFFER_SIZE];
uint8_t WAV_NextIndex = 0;
uint8_t WAV_PlayEnded = 0;
uint8_t WAV_PlayState = 0;
/* Private variables ---------------------------------------------------------*/
uint32_t WAV_Offset = 0;
uint32_t WAV_DataSize = 0;
uint32_t WAV_TxLength = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void I2S_MultiTimerCallback(MultiTimer *timer, void *userData)
{
WAV_PlaySong();
MultiTimerStart(&I2S_MultiTimer, 5000, I2S_MultiTimerCallback, "I2S");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void mI2S_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2S_InitTypeDef I2S_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S_Init(SPI1, &I2S_InitStructure);
SPI_DMACmd(SPI1, ENABLE);
I2S_Cmd(SPI1, ENABLE);
SPI1->GCTL |= (SPI_GCR_SPIEN | SPI_GCR_MODE | SPI_GCR_TXEN);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_6);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_6);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_6);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_6);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 |
GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_WriteBit(GPIOC, GPIO_Pin_2, Bit_RESET);
MultiTimerStart(&I2S_MultiTimer, 5000, I2S_MultiTimerCallback, "I2S");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void I2S_DMA_Transfer(uint16_t *Buffer, uint32_t BufferSize)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_DeInit(DMA1_Channel1);
RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->TXREG);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = BufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Auto_reload = DMA_Auto_Reload_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
if(DMA_InitStructure.DMA_PeripheralBaseAddr == ((uint32_t)(&(SPI1->TXREG))))
{
DMA_SetChannelMuxSource(DMA1_Channel1, DMA1_MUX_SPI1_TX);
if(DMA_GetChannelMuxSource(DMA1_Channel1) != DMA1_MUX_SPI1_TX)
{
while(1);
}
}
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
uint8_t WAV_DecodeFile(WAV_TypeDef *pWav, uint32_t Address)
{
ChunkRIFF_TypeDef *WAV_RIFF;
ChunkFMT_TypeDef *WAV_FMT ;
ChunkFACT_TypeDef *WAV_FACT;
ChunkDATA_TypeDef *WAV_DATA;
uint8_t WAV_HeadBuffer[512];
SPI_FLASH_FastRead(Address, WAV_HeadBuffer, 512);
/* 获取RIFF块 */
WAV_RIFF = (ChunkRIFF_TypeDef *)WAV_HeadBuffer;
/* 是WAV格式文件 */
if(WAV_RIFF->Format == 0x45564157)
{
/* 获取FMT块 */
WAV_FMT = (ChunkFMT_TypeDef *)(WAV_HeadBuffer+12);
/* 读取FACT块 */
WAV_FACT = (ChunkFACT_TypeDef *)(WAV_HeadBuffer+12+8+WAV_FMT->ChunkSize);
if((WAV_FACT->ChunkID == 0x74636166) || (WAV_FACT->ChunkID == 0x5453494C))
{
/* 具有FACT/LIST块的时候(未测试) */
pWav->DataStart=12+8+WAV_FMT->ChunkSize+8+WAV_FACT->ChunkSize;
}
else
{
pWav->DataStart=12+8+WAV_FMT->ChunkSize;
}
/* 读取DATA块 */
WAV_DATA = (ChunkDATA_TypeDef *)(WAV_HeadBuffer+pWav->DataStart);
/* 解析成功 */
if(WAV_DATA->ChunkID == 0x61746164)
{
pWav->AudioFormat = WAV_FMT->AudioFormat; /* 音频格式 */
pWav->nChannels = WAV_FMT->NumOfChannels; /* 通道数 */
pWav->SampleRate = WAV_FMT->SampleRate; /* 采样率 */
pWav->BitRate = WAV_FMT->ByteRate*8; /* 得到位速 */
pWav->BlockAlign = WAV_FMT->BlockAlign; /* 块对齐 */
pWav->BitsPerSample = WAV_FMT->BitsPerSample; /* 位数,16/24/32位 */
pWav->DataSize = WAV_DATA->ChunkSize; /* 数据块大小 */
pWav->DataStart = pWav->DataStart+8; /* 数据流开始的地方 */
printf("\r\npWav->AudioFormat : %d", pWav->AudioFormat);
printf("\r\npWav->nChannels : %d", pWav->nChannels);
printf("\r\npWav->SampleRate : %d", pWav->SampleRate);
printf("\r\npWav->BitRate : %d", pWav->BitRate);
printf("\r\npWav->BlockAlign : %d", pWav->BlockAlign);
printf("\r\npWav->BitsPerSample : %d", pWav->BitsPerSample);
printf("\r\npWav->DataSize : %d", pWav->DataSize);
printf("\r\npWav->DataStart : %d", pWav->DataStart);
WAV_Offset = pWav->DataStart + Address;
WAV_DataSize = pWav->DataSize;
}
}
return 0;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void WAV_PrepareData(void)
{
if(WAV_NextIndex == 0)
{
SPI_FLASH_FastRead(WAV_Offset + WAV_TxLength, WAV_DataBuffer[0], WAV_BUFFER_SIZE);
}
else
{
SPI_FLASH_FastRead(WAV_Offset + WAV_TxLength, WAV_DataBuffer[1], WAV_BUFFER_SIZE);
}
WAV_TxLength += WAV_BUFFER_SIZE;
if(WAV_TxLength > WAV_DataSize) WAV_PlayEnded = 1;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void WAV_PlayHandler(void)
{
if(WAV_PlayEnded == 0)
{
I2S_DMA_Transfer((uint16_t *)&WAV_DataBuffer[WAV_NextIndex][0], (WAV_BUFFER_SIZE / 2));
}
else
{
DMA_Cmd(DMA1_Channel1, DISABLE);
printf("\r\nWAV Play Finish!\r\n"); WAV_PlayState = 0;
}
if(WAV_NextIndex == 0) WAV_NextIndex = 1;
else WAV_NextIndex = 0;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void WAV_PlaySong(void)
{
WAV_TypeDef WaveFile;
if(WAV_PlayState == 0)
{
if(WAV_DecodeFile(&WaveFile, 0x00000000) == 0)
{
if((WaveFile.BitsPerSample == 16) && (WaveFile.nChannels == 2) &&
(WaveFile.SampleRate > 44000) && (WaveFile.SampleRate < 48100))
{
WAV_NextIndex = 0;
WAV_PlayEnded = 0;
WAV_TxLength = 0;
WAV_PlayState = 1;
printf("\r\n");
printf("\r\nWAV Data Size : %d, Data Start : 0x%08x", WAV_DataSize, WAV_Offset);
printf("\r\n");
WAV_PrepareData();
WAV_PlayHandler();
}
else
{
printf("\r\nWAV File Format Error!\r\n"); return;
}
}
else
{
printf("\r\nNo WAV File!\r\n"); return;
}
}
else
{
printf("\r\nThe Song Is Not Over Yet!\r\n");
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void DMA1_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC1);
WAV_PlayHandler();
}
if(DMA_GetITStatus(DMA1_IT_HT1) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_HT1);
WAV_PrepareData();
}
}
#endif
---------------------
作者:xld0932
链接:https://bbs.21ic.com/icview-3263182-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。