Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 11:44:42

Еще раз всем доброго дня.
Используя МК mega16 и (в будущем) MAX44007 (датчик освещения) планирую заставить их обмениваться информацией.
Знаю, что есть статья про цифровой люксометр, где все описано, прошу же помочь в "стартовом толчке".
Итак, пока мне нужно заставить обменяться информацией два MK mega16 в простом варианте: ведущий просит у ведомого байт, ведомый передает байт, ведущий зажигает светодиоды на одном из своих портов.

Используя библиотеку Procyon AVRLIB написал две следующих простых программки (дополнительно использую команды в виртуальный терминал для отладки в Proteus)

Master (ведущий)
Код:
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/interrupt.h>

#include "\i2c\deps\i2c.h"
#include "\i2c\deps\UART_routines.h"

#define LOCAL_ADDR 0xA0
#define TARGET_ADDR 0x07


unsigned char buf[100];
unsigned char msgbuf[100];



int main(void)
{
   uart0_init();
   _delay_ms(1000);
   sendStr0("*************TWI MASTER RUNNING*************");

   // initialize i2c function library
     i2cInit();
     // set local device address and allow response to general call
     i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);

   unsigned char mBuf[100];

   i2cMasterReceive(TARGET_ADDR, strlen(buf), buf);

sprintf(msgbuf,"master received: %s (length %d)",buf,strlen(buf));
     transmitString(msgbuf);
TX_NEWLINE;


Slave (ведомый)
Код:
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/interrupt.h>

#include "\i2c\deps\i2c.h"
#include "\i2c\deps\UART_routines.h"



#define LOCAL_ADDR 0x07
#define TARGET_ADDR 0xA0

unsigned char buf[40];
unsigned char byteToSend;
// slave operations
void i2cSlaveReceiveService(u08 receiveDataLength, u08* receiveData)
{
   sprintf(buf,"slave received: %s (length %d)",receiveData,receiveDataLength);
   transmitString(buf);TX_NEWLINE;
}

void i2cSlaveSendService(u08 transmitDataLength, u08 byteToSend)
{
   
   byteToSend=0b00111100;
   sprintf(buf,"slave sent: %s (length %d)",byteToSend,transmitDataLength);
   transmitString(buf);
   TX_NEWLINE;
   
}
int main(void)
{
   uart0_init();
   //_delay_ms(10);
   sendStr0("*************TWI SLAVE RUNNING*************");

   // initialize i2c function library
     i2cInit();
     // set local device address and allow response to general call
     i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);
   
   i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );
   i2cSetSlaveTransmitHandler(i2cSlaveSendService    );

   while(1)
   {
      _delay_ms(100);
   }
}


Протеус в своих терминалах грустно сообщает, что ведомый передал "нечто" (совпадения бит мне обнаружить не удалось), хотя команды старт и стоп передались нормально. Ведущий же ничего не получил. (длина 0)
Судя по всему, я просто где-то что-то не понимаю, потому что, к примеру, у мастера процедура i2cMasterReceive(TARGET_ADDR, strlen(buf), buf); не имеет возвращаемого значения, а записывает результат (как я понимаю) в buf.
Собственно, пока прошу помочь исправить программу так, чтобы она выполняла сей несложный алгоритм
Спасибо

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 14:32:23

если не ошибаюсь, то младший разряд адреса используется для широковещательных сообщений
0х07 = 0b00000111
возможно дело в адресе? для верности обратитесь в даташит

+++
и еще
i2cMasterReceive(TARGET_ADDR, strlen( buffer),&RecBuf[0]) ;

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 14:50:03

Дело врядли в адресе. Я эту программу взял из статьи-примера, но там мастер передает, ведомый принимает. Это работает (и у меня в протеусе). Но мне же нужно будет определенный адрес читать ибо люксометр точно будет ведомым.
Попытался переделать, но мимо.

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 14:53:52

посмотрите строку из моего примера (см выше). это работает - там адресация к буферу иначе сделана

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 16:22:03

Попробовал. Без перемен. slave sent 32(!!??), master received 0
Если дело и в этом, то не только в этом.
привожу пример кода мастера с исправлением, возможно я не так понял строчку кода.
Код:
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/interrupt.h>

#include "\i2c\deps\i2c.h"
#include "\i2c\deps\UART_routines.h"

#define LOCAL_ADDR 0xA0
#define TARGET_ADDR 0x07


unsigned char buf[100];
unsigned char msgbuf[100];



int main(void)
{
   uart0_init();
   _delay_ms(1000);
   sendStr0("*************TWI MASTER RUNNING*************");

   // initialize i2c function library
     i2cInit();
     // set local device address and allow response to general call
     i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);

   unsigned char mBuf[100];
//    sprintf(mBuf,"%s","hello!");
//    mBuf[strlen(mBuf)]=0x00;
    //i2cMasterSend(TARGET_ADDR,strlen(mBuf)+1/*(0x00)*/,&mBuf[0]);
   char RecBuf[100];
   i2cMasterReceive(TARGET_ADDR, strlen(buf), &RecBuf[0]);
//
sprintf(msgbuf,"master received: %s (length %d)",RecBuf,strlen(RecBuf)/*(0x00)*/);
     transmitString(msgbuf);
TX_NEWLINE;
   


Байт пытался передавать разных, в I2C debugger ничего не меняется
Последний раз редактировалось jakob291 Вт июл 31, 2012 16:46:45, всего редактировалось 1 раз.

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 16:39:17

Код:
 SPI debugger
а это здесь зачем?? вроде как i2c
0х07 = 0b00000111
младший разряд запись/чтение (1 чтение )
Широковещательный адрес 0

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 16:46:22

Код:
SPI debugger
а это здесь зачем?? вроде как i2c

Пардон, о чем думал, то и написал. I2C конечно же.
А вот с адресом... я все равно не понял что не так. 0x07 - адрес ведомого, которого я и читаю. Ведомый, будучи МК, сам его себе ставит. Широковещательный адрес мне здесь вроде не нужен, ибо он используется для того, чтобы все ведомые приняли сообщение от ведущего.
Попробовал поставить адресом ведомого 0x06 и обращаться к нему же - вообще ничего не меняется
Или дело в другом?

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 16:59:55

Нормально все с адресом. Всего кода же не видно, только часть. Без библиотеки.. А чё она там делает не понятно..
Может отладку вести например так, было прерывание по TWI вывести сообщение или лапкой дернуть. приняли свой адрес другой лапкой ..
Да и на дебугере протеуса видно аск был или нет. Сейчас хотя бы наладить аппаратную часть.

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 17:13:35

Судя по дебаггеру, был ACK. Хотя хрен его разберет, может и ошибаюсь.
Вот картинка Изображение

Жалко, что неясно, кто вел передачу в тот или иной момент. Но, как я понимаю, был старт, потом мастер послал адрес, а ведомый ответил ACK, затем ведомый передал "что-то" и отправил NAK, сообщая что передачу закончил.

Ведомый кстати передавал байт вида 0b11111000
И как я уже говорил, прямая передача получается "на ура", даже текст передается. А вот обратная...
Поэтому дело не в аппаратной части, а в программной, по крайней мере пока я не начал это все паять...

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 18:01:06

Код:
void i2cSlaveSendService(u08 transmitDataLength, u08 byteToSend)
{
   
   byteToSend=0b00111100;
   sprintf(buf,"slave sent: %s (length %d)",byteToSend,transmitDataLength);
   transmitString(buf);
   TX_NEWLINE;
   
}

попробуй так
Код:
u08 i2cSlaveSendService(u08 transmitDataLength, u08* byteToSend)
{
   
   *byteToSend=0b00111100;//записать в переменную по указателю byteToSend
   
 //  sprintf(buf,"slave sent: %s (length %d)",byteToSend,transmitDataLength);
  // transmitString(buf);
  // TX_NEWLINE;
   return 1;  //количество передаваемых байт у тебя один
}

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 18:27:54

Та же песня, даже в дебагере сообщение не поменялось.
Заставил ведомого подать +5 на PB0 при срабатывании SlaveSendService - срабатывает.
Что-то мне подсказывает, что у меня или обработчик неправильно задан, или мастер не оттуда берет этот самый бит. Просто мне подобная программная структура (когда нечто передается параметром в функцию и оно же выступает результатом) кажется какой-то несуразной. В C# так вообще нельзя (передаваемый параметр строго только для чтения), но по опыту, C/C++ иногда такие вещи допускают...

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 18:31:39

Можно весь проект увидеть?? Одним Архивом..

Re: обмен данными по i2c (от простого к сложному)

Вт июл 31, 2012 18:47:53

Нет проблем.
Только вопрос, сколько Вы его собирать воедино будете: 2 проекта AVR studio 5.1, мастер и ведомый. В папке deps - библиотечки и прочее для i2c (procyon)
И файл протеуса. Все с последними правками.
Вложения
i2c_oneByte.7z
Проект
(215.42 KiB) Скачиваний: 931

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 17:08:50

МК не успевает должным образом обрабатывать .
Код:
u08 i2cSlaveSendService(u08 transmitDataLength, u08* byteToSend)
{
   
   *byteToSend= 0x11;//записать в переменную по указателю byteToSend
     return 1;  //количество передаваемых байт у тебя один
}

Выход либо тактовую поднять у слейва, либо у мастера i2cSetBitrate(100); сделать меньше например 50.
Ну еще можно в библиотеке поковыряться.

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 17:30:13

Собственно, только и делаю, что ковыряюсь в библиотеке.
Только толковой документации нет.

Изменение битрейта, как я и предполагал, ничего не дало. В I2C debugger сообщение меняется если поменять число передаваемых бит. Но по-прежнему никакого соответствия я не наблюдаю...

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 18:03:09

У меня работает передает то что я назначил.
avr.7z
(5.32 KiB) Скачиваний: 889
0x11
только тактовую на слейве поднял до 8

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 18:35:42

Да, передача идет.
А именно код посмотреть можно? Интересная хрень с частотами, с чего бы ему не успевать...

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 18:52:24

avr.7z
(93.86 KiB) Скачиваний: 961
Вот только пути уже по другому, Я АВР студио не работал.

Код:
i2cMasterReceive(TARGET_ADDR, len, RecBuf);
в место лен нужно установить сколь байт считывать в твоем случае 1
и там ниже в мастере не обращай внимания.

Re: обмен данными по i2c (от простого к сложному)

Ср авг 01, 2012 20:08:43

Ух, работает хреновина)
Самое страшное, это же была только имитация реальности) Теперь предо мной встает датчик. А у датчика измерения хранятся в двух байтах, в двух регистрах. А адрес у датчика один)
В общем, спасибо за помощь. Тему не закрываю, то ли еще будет)

Re: обмен данными по i2c (от простого к сложному)

Чт авг 02, 2012 19:40:50

И еще как небольшие рекомендации для мастера уметь дрыгать ножкой клок программно. Спасает при коллизиях на шине. Можно засунуть в процесс инициализации шины.
И для слейв устройств проходить переинициализацию шины если в течении какого времени мастер не обращается к ниму..
Тема закрыта