我用的单片机型号是STM32G030C8T6,环境使用CUBEMX生成的代码,采用硬件I2C方式。
问题:
我想用I2C+DMA的方式去读写AT24C02,往里面写入0~0xff,然后读取出来。但是写入不了,调试的时候发现设备状态一直是繁忙,不会返回应答。
/* USER CODE BEGIN PV */
#define PAGE_SIZE_24CXX 8
#define PAGE_NUM_24CXX 32
#define ADDR_24CXX 0xA0
#define I2C_24CXX hi2c1
#define ADD_SIZE_24CXX I2C_MEMADD_SIZE_8BIT
int i;
uint8_t WriteBuffer[PAGE_SIZE_24CXX*PAGE_NUM_24CXX] = {0};
uint8_t ReadBuffer[PAGE_SIZE_24CXX*PAGE_NUM_24CXX] = {0};
/* USER CODE END PV */
/* USER CODE BEGIN 0 */
HAL_StatusTypeDef I2C_WaitUntilDeviceReady(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint32_t Timeout){
uint32_t tickstart = HAL_GetTick(); //获取当前时间
while(HAL_GetTick()-tickstart <= Timeout){ //如果没有超时就一直尝试
if(HAL_I2C_IsDeviceReady(hi2c, DevAddress,1, Timeout) == HAL_OK){ //如果准备好了就return
return HAL_OK;
}
}
return HAL_TIMEOUT; //否则return一个错误
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
int e;
for(i=0; i < PAGE_SIZE_24CXX*PAGE_NUM_24CXX; i++) {WriteBuffer[i] = i;} //初始化要写入的数组
uint32_t TickStart=HAL_GetTick(); //获取当前时间戳
for (int j=0; j < PAGE_NUM_24CXX; j++)//页写入
{
I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 10);//自己写的等待函数
e = HAL_I2C_Mem_Write_DMA(&I2C_24CXX, ADDR_24CXX, PAGE_SIZE_24CXX*j, \
ADD_SIZE_24CXX, WriteBuffer+PAGE_SIZE_24CXX*j, PAGE_SIZE_24CXX);//向每一页都写入数据
if (e == HAL_OK) {
printf("第%d页已写入,time=%lu ms\r\n", j,HAL_GetTick());//输出页写时间
} else {
printf("EEPROM写入出错 ,j=%d,error=%d\r\n", j, e);
}
}
printf("%d次页写共用时%lu ms\r\n",PAGE_NUM_24CXX, HAL_GetTick() - TickStart);//输出总用时
I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 20);
e = HAL_I2C_Mem_Read_DMA(&I2C_24CXX, ADDR_24CXX, 0, ADD_SIZE_24CXX,\
ReadBuffer, PAGE_SIZE_24CXX*PAGE_NUM_24CXX);//读取数据
if(e==HAL_ERROR)
printf("EEPROM读取出错 %d\r\n",e);
else
for(i=0; i<PAGE_NUM_24CXX; i++){
for(int j=0; j<PAGE_SIZE_24CXX; j++){
printf("%2x ", ReadBuffer[i*8+j]);
}
printf("\r\n");
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
但是我不用DMA的方式,直接用轮询就没问题,代码也就只改了写入和读取的函数。
int e;
for(i=0; i < PAGE_SIZE_24CXX*PAGE_NUM_24CXX; i++) {WriteBuffer[i] = i;} //初始化要写入的数组
uint32_t TickStart=HAL_GetTick(); //获取当前时间戳
for (int j=0; j < PAGE_NUM_24CXX; j++)//页写入
{
I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 10);//自己写的等待函数
e = HAL_I2C_Mem_Write(&I2C_24CXX, ADDR_24CXX, PAGE_SIZE_24CXX*j, \
ADD_SIZE_24CXX, WriteBuffer+PAGE_SIZE_24CXX*j, PAGE_SIZE_24CXX, 1000);//向每一页都写入数据
if (e == HAL_OK) {
printf("第%d页已写入,time=%lu ms\r\n", j,HAL_GetTick());//输出页写时间
} else {
printf("EEPROM写入出错 ,j=%d,error=%d\r\n", j, e);
}
}
printf("%d次页写共用时%lu ms\r\n",PAGE_NUM_24CXX, HAL_GetTick() - TickStart);//输出总用时
I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 20);
e = HAL_I2C_Mem_Read(&I2C_24CXX, ADDR_24CXX, 0, ADD_SIZE_24CXX,\
ReadBuffer, PAGE_SIZE_24CXX*PAGE_NUM_24CXX, 1000);//读取数据
if(e==HAL_ERROR)
printf("EEPROM读取出错 %d\r\n",e);
else
for(i=0; i<PAGE_NUM_24CXX; i++){
for(int j=0; j<PAGE_SIZE_24CXX; j++){
printf("%2x ", ReadBuffer[i*8+j]);
}
printf("\r\n");
}