Миландр 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 шт):

Автор решения: Lampadov

Запросили у Вас контактные данные, просьба, пожалуйста, выслать по электронной почте [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).

Данный алгоритм позволит однозначно точно добиться корректного чтения данных нужного регистра из магнитометра. Пожалуйста, скорректируйте программный код.

С наилучшими пожеланиями, Лампадов Илья Отдел технической поддержки АО "ПКК Миландр"

→ Ссылка