STM32 设置I2C从机模式DMA中断接收
周末摆弄了一天,被各种垃圾文档啥的淹没不知所措,自己最后研究出来了之后不知道发哪,想来想去发B站专栏得了。(强烈需求专栏支持markdown)
需求是这样的:俺手里有一个STM32F407 开发板(以下简称STM32),还有一个树莓派PICO(以下简称树莓派),想试一下两者通过I2C进行数据对发。俺寻思把STM32作为从机,树莓派作为主机,使用树莓派每100ms发送消息给从机,从机接收。
硬件连线如下

树莓派代码如下(基于micropython)

STM32 CUBEMX生成器管脚配置如图





【用来和上位机通信的UART配置,不需要的话可以不管】
这里实现的是烂大街的空闲中断接收任意长度的UART




STM32代码部分:




【重点】在stm32f4xx_it.c中


【附录】:在main.h中做如下的extern

运行结果:串口打印:


树莓派代码源码如下:
from machine import I2C,Pin
from utime import sleep
i2c= I2C(0,sda=Pin(0),scl=Pin(1),freq=100000)
buf = b'this is i2c hello'
if __name__ == '__main__':
while True:
i2c.writeto(32,buf)
print('send buf')
sleep(0.1)

STM32重要代码块如下:

main.c内
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
uint8_t receive_num;
uint8_t i2c_receive_num;
uint8_t u1_rec_buf[MAX_BUF];
uint8_t i2c_rec_buf[MAX_BUF];
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
#pragma import(__use_no_semihosting)
struct __FILE {
int handle;
};
FILE __stdout;
void _sys_exit(int x){
x = x;
}
int fputc(int ch, FILE* stream)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFFF);
return ch;
}
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
extern DMA_HandleTypeDef hdma_i2c1_rx;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);
HAL_I2C_Slave_Receive_DMA(&hi2c1,i2c_rec_buf,MAX_BUF);
printf("ALL INIT OK\n");
printf("I2C1 WORKMODE %d\n",HAL_I2C_GetMode(&hi2c1));
/* USER CODE END 2 */

main.h内
/* USER CODE BEGIN EC */
#define MAX_BUF 200
extern uint8_t u1_rec_buf[];
extern uint8_t receive_num;
extern uint8_t i2c_receive_num;
extern uint8_t i2c_rec_buf[];
/* USER CODE END EC */

stm32f4xx_it.c内
void DMA1_Stream0_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream0_IRQn 0 */
/* USER CODE END DMA1_Stream0_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_i2c1_rx);
/* USER CODE BEGIN DMA1_Stream0_IRQn 1 */
i2c_receive_num = MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_i2c1_rx);
printf("Receive : %d\n",i2c_receive_num);
printf("%s\n",i2c_rec_buf);
HAL_I2C_Slave_Receive_DMA(&hi2c1,i2c_rec_buf,MAX_BUF);
/* USER CODE END DMA1_Stream0_IRQn 1 */
}
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)==SET)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
receive_num=MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}