LINUX.ORG.RU

Проблема с I2C в MSP430

 , , ,


0

1

Имею MSP430F5529 Launchpad. Хочу считывать данные с датчиков по I2C и столкнулся с проблемой - I2C работает нормально только после перепрошивки. То есть, загружаю я прошивку с помощью программатора-отладчика Ez-FET, установленного на плате, - всё работает нормально. Можно жать кнопочку RESET, можно запускать отладку - всё будет работать нормально. Но если ввести МК в режим BSL (зажать кнопки BSL и RESET, затем отпустить сначала RESET и только потом BSL), а потом перезагрузить или отключить питание платы, а потом подключить снова, то I2C не работает. И не будет работать, сколько не перезагружай плату. Но стоит залить ТУ ЖЕ САМУЮ прошивку и всё начинает работать. При этом таймеры, UART и GPIO работают как надо всегда (другие модули не использую пока что). Если не заливать заново прошивку, а подключиться для отладки это проблему не решает. Надо именно перезалить прошивку. То есть какая-то инициализация осуществляется программатором при заливке прошивки, а я в своей программе её не делаю. Для того чтобы внешние датчики всегда были в одинаковом состоянии запитал их от GPIO микроконтроллера, благо они жрут единицы миллиампер. Так что на них никак не влияет перепрошивка - они начинают работать с нуля каждый сброс МК (МК при старте сначала выдаёт 0 на питание датчиков, ждёт кучу времени, чтобы точно разрядились все конденсаторы и лишь потом запитывает датчики).

Если плату отключить от питания и быстро подключить снова, то она может и заработать. Также она работает, если отключали только питание, а внешний переходник на UART остался подключен и мог питать МК с помощью паразитного питания через подтяжки линий (но при этом МК не исполнял программу, для этого питания не хватало, но, возможно, мог сохранить состояние ОЗУ или какой-то периферии), а затем подали питание вновь.

Вот код моей библиотеки для работы с I2C: http://pastebin.com/M1WtDKQb. Я не нашёл отличий в инициализации от примеров TI.

«Не работает» - значит любые попытки чтения по I2C возвращают не то, что нужно. Обычно это нули. Но после режима BSL это значение 0xC7.

В чём может быть дело? Какое состояние МК может инициализировать программатор при прошивки и оно сохраняется при перезагрузках, но не сохраняется при пропадании питания.

Смотрел с помощью mspdebug содержимое памяти по тем адресам, где находятся регистры, которые отвечают за I2C - различия между ситуациями, когда работает и когда нет, нету, всё настроено идентично. Больше не знаю, что посмотреть.

★★★★★

Последнее исправление: KivApple (всего исправлений: 1)

Ответ на: комментарий от qbe

Вот так работает нормально:

int32_t tmp = (((int16_t)BYTE_SWAP(mpu6050_response[3])) * (int32_t)100);
temperature = tmp / 340 + 3653;

При том если приводить результат BYTE_SWAP к int32_t, то не работает.

Но блин... как может простое умножение int на float работать так долго. При том что у MSP430 в два раза шире разрядность и есть аппаратный умножитель.

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Но блин... как может простое умножение int на float работать так долго.

Если к бочке меда добавить ложку говна, то будет бочка говна. Умножение int на float выполняется так, что int преобразуется во float и они умножаются как float на float.

И долго - это понятие относительное. Скорости MSP430 и AVR - это еще бабушка на двое сказала. А программная реализация арифметики в FP - это вещь такая. Ну и что, что 16 МГц vs 20 МГц и 8 vs 16 бит. Тем более, что математика FP в MSPGCC написана на Си и неоптимальна, скорее всего.

И странно, что у тебя компилятор константы заранее не считает из выражений. У тебя оптимизация какая используется?

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 2)
Ответ на: комментарий от Zubok

Пробовал -Os и -O2. При этом код получается одинакового размера.

Умножение выглядит как-то так:

MOV.W	8(R7), R13 # Тут он извлекает int16_t из массива
MOV.W	R13, R12
rpt	#8 { rlax.w	R12
rrum.w	#4, R13 { rrum.w	#4, R13 
BIS.W	R13, R12
MOV.W	#__mspabi_fltlid, R4
BIT.W	#0x8000, R12 { SUBC.W	R13, R13 { INV.W	R13, R13
CALL	R4
MOV.W	#__mspabi_mpyd, R5
MOV.W	R12, R8
MOV.W	R13, R9
MOV.W	R14, R10
MOV.W	R15, R11
MOV.W	#-19705, R12
MOV.W	#-1404, R13
MOV.W	#29706, R14
MOV.W	#16193, R15
CALL	R5
MOV.W	#__mspabi_cvtdf, R6
CALL	R6
MOV.W	R12, &gyro_x
MOV.W	R13, &gyro_x+2
KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

Умножение выглядит как-то так:

Ну как бы все нормально выглядит.

r8, r9, r10, r11 - один операнд, r12, r13, r14, r15 - второй операнд (твоя FP константа в IEEE 754). далее вызов _mpyd - это умножение, потом конвертация результата _cvtdf и запись его в gyro. _fltlid - это, наверное, преобразование int во float. Полагаю.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 5)
Ответ на: комментарий от Zubok

Я не понял как эту штуку использовать с mspgcc, а не платным компилятором от TI. Ссылка на скачивание перенаправляет на Code Composer Studio.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

А ты float используешь или double? Что-то не могу понять, почему константа - четыре 16-битных числа. Получается 64 бита, то есть double. Или я что-то не так понял. Какой код точно соответсвует этому ассемберу? Покажи. И как объявлено все. Наверное, он твою константу считает как double precision. И, соотв., использует более медленную арифметику.

Я не понял как эту штуку использовать с mspgcc, а не платным компилятором от TI. Ссылка на скачивание перенаправляет на Code Composer Studio.

А ХЗ. Одно понятно, что там mspgcc не приоритет, кажется. Зачем писать свою библиотеку вместо оптимизации стандартных функций.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 6)
Ответ на: комментарий от Zubok

Было так:

gyro_x = ((int16_t)BYTE_SWAP(mpu6050_response[4])) * 0.000532632218016; // / 32.768 * M_PI / 180.0;
gyro_y = ((int16_t)BYTE_SWAP(mpu6050_response[5])) * 0.000532632218016; // / 32.768 * M_PI / 180.0;
gyro_z = ((int16_t)BYTE_SWAP(mpu6050_response[6])) * 0.000532632218016; // / 32.768 * M_PI / 180.0;

Сделал так:

gyro_x = ((int16_t)BYTE_SWAP(mpu6050_response[4])) * (float)0.000532632218016; // / 32.768 * M_PI / 180.0;
gyro_y = ((int16_t)BYTE_SWAP(mpu6050_response[5])) * (float)0.000532632218016; // / 32.768 * M_PI / 180.0;
gyro_z = ((int16_t)BYTE_SWAP(mpu6050_response[6])) * (float)0.000532632218016; // / 32.768 * M_PI / 180.0;

И всё стало хорошо. Теперь скорость работы вполне сравнима с AVR.

На AVR у меня в принципе не работал double. Если описать double переменную, то она всё равно занимала 4 байта. А на MSP430 похоже double таки реализован. А gcc хочет использовать его по умолчанию.

Код похудел на пару килобайт, умножение теперь выглядит так:

MOV.W	8(R7), R13
MOV.W	R13, R12
rpt	#8 { rlax.w	R12
rrum.w	#4, R13 { rrum.w	#4, R13 
BIS.W	R13, R12
MOV.W	#__mspabi_fltlif, R9
BIT.W	#0x8000, R12 { SUBC.W	R13, R13 { INV.W	R13, R13
CALL	R9
MOV.W	#__mspabi_mpyf, R10
MOV.W	#-24488, R14
MOV.W	#14859, R15
CALL	R10
MOV.W	R12, &gyro_x
MOV.W	R13, &gyro_x+2

Проблема решена, всем спасибо за подсказки.

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 6)
Ответ на: комментарий от KivApple

(float)0.000532632218016

0.000532632218016f ? :) Ну и имей в виду точность float, чтобы потом из за этого дальнейшие вычисления не пострадали. Есть смысл проанализировать потерю точности.

Zubok ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.