如果我把下面代码中的
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
这句屏蔽,就不会出现HardFault,并且ADC采集的到数据是正常的。
已经折腾了一天木有结果,,求大神指点
uint16_t ADCConvertedValue[256];
uint8_t DisplayRAM[1024];
void RCC_Configuration(void)
{
//ADCCLK由 PCLK2(72MHz) 6分频 得到 12MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//启用 DMA1
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//启用ADC1 GPIOA SPI1 USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA |
RCC_APB2Periph_SPI1 | RCC_APB2Periph_USART1, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//PA1 (ADC1 Channel 1)模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PA5:SPI1_SCK PA7:SPI1_MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//PA4:OLED的D/C作为数据/命令选择线 PA6:OLED_RST
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//PA9:USART1 Tx 作为功能引脚并上拉输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PA10 USART1 Rx 作为功能引脚并是浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
//115200 8n1
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
//重定向 printf 函数打印信息的 putchar 函数
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
int __io_putchar(int ch)
#else
int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
{
//等待可以发送数据
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
//串口发送字符
USART_SendData(USART1, (uint8_t) ch);
return ch;
}
void InitADC(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitDef;
//配置 ADC1
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/*----------------------------------------------------------------------------
输入信号是 20000Hz,每个周期采样 2 个点,每秒要采样 40000 点。
点间隔 1s / 40000 = 25us,ADC时钟频率 12MHz,所以采样周期 25us / 12MHz = 300
需要每300个 ADC 周期采样一个点,但是周期最多只能配置为 239.5
所以采集能力最终是每秒 50000 点
----------------------------------------------------------------------------*/
//ADC1 通道1配置
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
//启用 ADC1 DMA
ADC_DMACmd(ADC1, ENABLE);
//启用ADC1
ADC_Cmd(ADC1, ENABLE);
//ADC1 复位校准并等待结束
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
//ADC1 开始校准并等待结束
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
//配置 DMA 通道1(ADC1) IRQ 中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitDef.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitDef.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitDef.NVIC_IRQChannelSubPriority = 0;
NVIC_InitDef.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitDef);
//配置 DMA1 通道1
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;
printf("%x %x\r\n", DMA_InitStructure.DMA_PeripheralBaseAddr, DMA_InitStructure.DMA_MemoryBaseAddr);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 256;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
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_Init(DMA1_Channel1, &DMA_InitStructure);
//启用 DMA1 通道1 传输完成中断
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
//启用 DMA1 通道1
DMA_Cmd(DMA1_Channel1, ENABLE);
printf("ADC start conv\r\n");
//ADC1 开始采集
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
void DMA1_Channel1_IRQHandler(void)
{
printf("DMA1_Channel1_IRQHandler\n");
if(DMA_GetITStatus(DMA1_IT_TC1))
{
//通道1传输完成,清DMA发送完成标志
DMA_ClearFlag(DMA1_FLAG_TC1);
printf("DMA1_Channel1_IRQHandler\n");
}
}
void InitSPI(void)
{
DMA_InitTypeDef DMA_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
//配置 DMA1 通道3 负责 SPI1 发送
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DisplayRAM;
printf("%x %x\r\n", DMA_InitStructure.DMA_PeripheralBaseAddr, DMA_InitStructure.DMA_MemoryBaseAddr);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = sizeof(DisplayRAM);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/*----------------------------------------------------------------------------
配置 SPI1
主机模式
只发送不接收
空闲时 SCLK 高电平
SCLK由低跳变到高时数据有效
16 分频得到 4.5M SPI
无CRC
----------------------------------------------------------------------------*/
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI1,&SPI_InitStructure);
SPI_Cmd(SPI1,ENABLE);
//启用 SPI DMA 发送
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
}
void OledWrite(uint8_t data)
{
//等待缓冲
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, data);
//返回时SPI并没有发送完数据,因为SPI状态没有TC标志,因此需要小心处理
}
void OledCmdMode()
{
//PA4(D/C) = 0 发送命令
Delay_ms(1); //等待未发送完成的数据
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
}
void OledDataMode()
{
//PA4(D/C) = 1 发送命令
Delay_ms(1); //等待未发送完成的数据
GPIO_SetBits(GPIOA, GPIO_Pin_4);
}
void OledRefresh()
{
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_ClearITPendingBit(DMA1_IT_GL3); //清除所有标志
DMA1_Channel3->CNDTR = 1024; //重设接收长度
DMA1_Channel3->CMAR = (uint32_t)DisplayRAM; //重设缓冲区
DMA_Cmd(DMA1_Channel3, ENABLE);
//等待发送完成
while (!DMA_GetFlagStatus(DMA1_FLAG_TC3));
}
void InitOled()
{
//复位 OLED 并保持 OLED RST 低电平 1 毫秒
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
Delay_ms(1);
//RST 拉高并保持 10 微妙后才发送命令
GPIO_SetBits(GPIOA, GPIO_Pin_6);
Delay_us(10);
//命令模式
OledCmdMode();
//初始化序列
OledWrite(0xAE); //set display off
OledWrite(0xD5); //set display clock divide ratio/oscilator frequency
OledWrite(0x80);
OledWrite(0xA8); //set multiplex ratio
OledWrite(0x3F);
OledWrite(0xD3); //set display offset
OledWrite(0x00);
OledWrite(0x40); //set display start line
OledWrite(0x8D); //set charge pump
OledWrite(0x14);
OledWrite(0xA1); //set segment re-map
OledWrite(0xC8); //set COM output scan direction
OledWrite(0xDA); //set COM pins hardware configuration
OledWrite(0x12);
OledWrite(0x81); //set contrast control
OledWrite(0x8F);
OledWrite(0xD9); //set pre-charge period
OledWrite(0xF1);
OledWrite(0xDB); //set VCOMH deselect level
OledWrite(0x30);
OledWrite(0xA4); //set entire display on/off
OledWrite(0xA6); //set normal/inverse display
//clear screen
//delay recommended
Delay_ms(10);
OledWrite(0xAF); //set display on
Delay_ms(100); //100ms delay recommended
//设置为列扫描模式
OledWrite(0x20); //set addressing mode
OledWrite(0x01); //00水平页扫 01垂直列扫 02页模式
//设置页起始地址和列起始地址(仅页模式可用)
/*
OledWrite(0xb0); //set page start address for page addressing mode, b0-b7 = page0-page7
OledWrite(0x00); //set lower 4bit column start address for page addressing mode (00h-0fh)
OledWrite(0x10); //set higher 4bit column start address for page addressing mode (10h~1fh)
*/
//设置起始页结束页和起始列结束列(仅 水平页扫 垂直列扫 可用)
OledWrite(0x21); //set column start and end address
OledWrite(0x00); //start column 0-127
OledWrite(0x7F); //end column 0-127
OledWrite(0x22); //set page start and end address
OledWrite(0x00); //start page 0-7
OledWrite(0x7F); //end page 0-7
//数据模式
OledDataMode();
}
int main()
{
SystemInit();
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
printf("InitSPI\r\n");
InitSPI();
printf("InitADC\r\n");
InitADC();
printf("InitOled\r\n");
InitOled();
while(1)
{
printf("%x %x\r\n",ADCConvertedValue[0], ADCConvertedValue[1]);
memset(DisplayRAM,0xff,1);
OledRefresh();
Delay_ms(500);
memset(DisplayRAM,0,1024);
OledRefresh();
Delay_ms(500);
}
while(1);
} |