Миландр MDR32F9Q2 считывание данных с магнетометра MPU9250 по интерфейсу I2C
Доброго дня/вечера форумчане, нужна помощь в понимании как программировать интерфейс I2C на отечественном микроконтроллере от "Миландр" MDR32F9Q2.
Функция инициализации интерфейса:
void I2C_init(void)
{
/*Настройка порта*/
MDR_RST_CLK->PER_CLOCK |= RST_CLK_PCLK_PORTC;
MDR_PORTC->FUNC &= ~(PORT_FUNC_MODE0_Msk
| PORT_FUNC_MODE1_Msk);
MDR_PORTC->FUNC |= (PORT_FUNC_ALTER << PORT_FUNC_MODE0_Pos
| PORT_FUNC_ALTER << PORT_FUNC_MODE1_Pos);
MDR_PORTC->ANALOG |= PORT_Pin_0
| PORT_Pin_1;
MDR_PORTC->PWR |= (PORT_SPEED_MAXFAST << PORT_PWR0_Pos
| PORT_SPEED_MAXFAST << PORT_PWR1_Pos);
/*Настройка I2C*/
MDR_RST_CLK->PER_CLOCK |= RST_CLK_PCLK_I2C; /*Включение тактирования*/
MDR_I2C->PRL = 0x27;
MDR_I2C->PRH = 0;
MDR_I2C->CTR |= (1 << I2C_CTR_EN_I2C_Pos) /*Включение приемопередатчика*/
| (0 << I2C_CTR_EN_INT_Pos) /*Запрет прерываний*/
| (0 << I2C_CTR_S_I2C_Pos); /*CLK до 400кГц*/
}
Проверил осциллографом частоту на линии SCL, при непрерывной отправке байт, равна она ~400кГЦ(396кГц если точно). Написал небольшой скрипт для считывания данных с регистра магнитометра:
I2C_Send7bitAddress(0x1C, I2C_Direction_Transmitter); /*Передача адреса магнитометра и бита записи*/
while(MDR_I2C->STA & I2C_STA_RX_ACK){}; /*Ожидание от слейва ACK бита*/
I2C_SendByte(0x00); /*Отправка номера регистра, который хочу считать*/
while(MDR_I2C->STA & I2C_STA_RX_ACK){}; /*Ожидание от слейва ACK бита*/
I2C_SendSTOP(); /*Отправка стоп-бита*/
I2C_Send7bitAddress(0x1C, I2C_Direction_Receiver); /*Передача адреса магнитометра и бита чтения*/
I2C_StartReceiveData(I2C_Send_to_Slave_NACK); /*Перевод микроконтроллера в режим чтения*/
while(MDR_I2C->STA & I2C_STA_RX_ACK){}; /*Ожидание от слейва ACK бита*/
while(MDR_I2C->STA & I2C_STA_TR_PROG) /*Пока передаются данные*/
{
temp[idx] = I2C_GetReceivedData(); /*Считать байт*/
idx++;
}
I2C_SendSTOP(); /*Отправка стоп-бита*/
Вроде бы все сделал согласно даташиту на магнитометр, рисунок с алгоритмом чтения 1 байта прилагаю ниже

Но вместо того чтобы получить в ответ 1 байт равный 0x48, я получаю массив состоящий из 35 элементов и ни в одной из ячеек нет нужного байта
Первый байт будто бы просто равен значению которое я отсылаю вместе с битом записи 0x1C | 0x00, а следующие 4 значения это адрес с битом чтения 0x1C | 0x01. Почему эти данные остаются в буфере к моменту чтения, учитывая что я жду подтверждающий бит от слейва, я не понимаю. Заранее спасибо за помощь
Ответы (1 шт):
Запросили у Вас контактные данные, просьба, пожалуйста, выслать по электронной почте [email protected].
Предварительно ошибка связана с тем, что стоповый бит по Вашему коду вдвигается на линию в середине транзакции. Документация на магнитометр регламентирует, что стоповый бит выставляется только в конце, до этого момента обработка на стороне ведущего (микроконтроллера) должна выполняться следующим образом:
- Ожидаем освобождения шины I2C (контроль флага BUSY);
- Задаем адрес устройства и признак ЗАПИСИ (R/W = 0);
- Отправляем признак START и инициируем саму передачу с данными из п.2 на стороне контроллера (регистр CMD);
- Ожидаем завершения передачи получением бита подтверждения ACK (а также контролем бита TR_PROG в регистре STA);
- Отправляем адрес регистра для чтения;
- Ожидаем завершения передачи получением бита подтверждения ACK (а также контролем бита TR_PROG в регистре STA);
- Задаем адрес устройства и признак ЧТЕНИЯ (R/W = 1);
- Отправляем повторно признак START и инициируем передачу с данными из п.7 на стороне контроллера (регистр CMD);
- Ожидаем завершения передачи получением бита подтверждения ACK (а также контролем бита TR_PROG в регистре STA);
- Инициируем приём данных и отправляем бит NACK для завершения передачи (регистр CMD);
- Читаем принятые данные из регистра RXD (без цикла, достаточно один раз);
- Отправляем признак STOP на шину (регистр CMD).
Данный алгоритм позволит однозначно точно добиться корректного чтения данных нужного регистра из магнитометра. Пожалуйста, скорректируйте программный код.
С наилучшими пожеланиями, Лампадов Илья Отдел технической поддержки АО "ПКК Миландр"

