1、开启DMA时钟
2、这里要开启I2C EVT事件中断,当地址匹配后清除地址中断标志才能继续发送数据
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/******* I2C1 DMA Channel Configuration **********/
DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_BufferSize = 10;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)read_buffer;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&I2C1->DR);
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel7,&DMA_InitStructure);
/******** DMA NVIC Configuration *****************/
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1,I2C_IT_EVT,ENABLE);
DMA_ITConfig(DMA1_Channel7,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA1_Channel7,ENABLE);
I2C_DMACmd(I2C1,ENABLE);
I2C_Cmd(I2C1,ENABLE);
void I2C_Configuration(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/******* I2C1 DMA Transmit Configuration **********/
DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_BufferSize = 10;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)write_buffer;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&I2C1->DR);
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel6,&DMA_InitStructure);
/******** DMA NVIC Configuration *****************/
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1,I2C_IT_EVT,ENABLE);
DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA1_Channel6,ENABLE);
I2C_Cmd(I2C1,ENABLE);
I2C_DMACmd(I2C1,ENABLE);
}
void I2C1_EV_IRQHandler(void)
{
if(I2C_GetITStatus(I2C1,I2C_IT_ADDR) != RESET)
{
assert_param(I2C1->SR2);
DMA_ClearITPendingBit(DMA1_IT_TC6);
DMA_Cmd(DMA1_Channel6,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel6, 10);
DMA_Cmd(DMA1_Channel6,ENABLE);
}
switch(I2C_GetLastEvent(I2C1))
{
case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
I2C_ClearITPendingBit(I2C1,I2C_IT_ADDR);
test++;
break;
/******* Slave transmit mode ************/
case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
I2C_SendData(I2C1,write_buffer[Tx++]);
break;
/******* Slave receive mode *************/
case I2C_EVENT_SLAVE_BYTE_RECEIVED:
read_buffer[Rx++] = I2C_ReceiveData(I2C1);
break;
case I2C_EVENT_SLAVE_STOP_DETECTED:
Rx = 0;
I2C_Cmd(I2C1,ENABLE);
break;
}
}
void DMA1_Channel6_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC6) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC6);
}
}
1、DMA正确的重新开启方法:先Disable,用库函数SetCurrDataCounter重新配置DMA缓冲区大小(因为DMA传输时这个大小值会递减至0所以需要重新配置),最后再使能DMA通道
DMA_Cmd(DMA1_Channel6,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel6, 10);
DMA_Cmd(DMA1_Channel6,ENABLE);
2、关于I2C的地址匹配中断,经测试发现,如果采用case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:和case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:这两个事件判断,然后I2C_ClearITPendingBit(I2C1,I2C_IT_ADDR);这种方式下,ADDR地址匹配中断只进一次
查阅void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT)库函数的说明有这样一段
/ *
* @note
* - STOPF (STOP detection) is cleared by software sequence: a read operation
* to I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
* I2C_CR1 register (I2C_Cmd() to re-enable the I2C peripheral).
* - ADD10 (10-bit header sent) is cleared by software sequence: a read
* operation to I2C_SR1 (I2C_GetITStatus()) followed by writing the second
* byte of the address in I2C_DR register.
* - BTF (Byte Transfer Finished) is cleared by software sequence: a read
* operation to I2C_SR1 register (I2C_GetITStatus()) followed by a
* read/write to I2C_DR register (I2C_SendData()).
* - ADDR (Address sent) is cleared by software sequence: a read operation to
* I2C_SR1 register (I2C_GetITStatus()) followed by a read operation to
* I2C_SR2 register ((void)(I2Cx->SR2)).
* - SB (Start Bit) is cleared by software sequence: a read operation to
* I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
* I2C_DR register (I2C_SendData()).
* @retval None
*/
这里指出了ADDR标志位清除的正确方法,先用I2C_GetITStatus()对SR1寄存器进行读操作,之后再对SR2寄存机进行读操作,才能正确清除ADDR标志
所以正确的清除方法应该是在EVT中断中作如下处理:
if(I2C_GetITStatus(I2C1,I2C_IT_ADDR) != RESET)
{
assert_param(I2C1->SR2);
}
STM32070RB主机 DMA中断发送
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
/******** I2C1 DMA Transmit Channel configuration *******/
DMA_DeInit(DMA1_Channel2);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&I2C1->TXDR);
DMA_InitStruct.DMA_BufferSize = 10;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)write_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium ;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_Init(DMA1_Channel2,&DMA_InitStruct);
/******** I2C1 NVIC Configurations *************/
NVIC_InitStruct.NVIC_IRQChannel = I2C1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0x02;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
I2C_ITConfig(I2C1, I2C_IT_ADDRI, ENABLE);
DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA1_Channel2,ENABLE);
I2C_Cmd(I2C1,ENABLE);
I2C_DMACmd(I2C1,I2C_DMAReq_Tx,ENABLE);
}
void DMA1_Channel2_3_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC3);
}
if(DMA_GetITStatus(DMA1_IT_TC2) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_Cmd(DMA1_Channel2,DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel2,10);
DMA_Cmd(DMA1_Channel2,ENABLE);
}
}