Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: avr155
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
alux
Разбираюсь с этим апнотом. Не понятно, каким образом в функции Get_byte() происходит обнаружение приема последнего байта? Ведь переменная j, которая передается в качестве второго аргумента этой функции, и которая сравнивается с нулем, инкрементируется data_pack.size раз и по идее не станет равной нулю ни при каких условиях. Ну, разве что размер получаемых данных превысит 255. Или я чего-то не доганяю?
На всякий случай прилагаю апнот.

Может быть правильней было бы сделать так:
for(j=data_pack.size;((j)&&(state == SUCCESS));j--)
state = Get_byte(data_pack.data_ptr++,j);
defunct
Цитата(alux @ Jul 19 2007, 14:07) *
Разбираюсь с этим апнотом. Не понятно, каким образом в функции Get_byte() происходит обнаружение приема последнего байта?

У функции Get_Byte - last_byte - это параметр, он из-вне задается.
Смысл конечно искажен немного, т.к. судя по отправке ACK/NACK - last_byte == 0 - означает последний принимаемый байт.

Цитата
for(j=0;((j<data_pack[i].size)&&(state == SUCCESS));j++)
state = Get_byte(data_pack[i].data_ptr++,j);

Это оригинал? smile.gif
Тут только два варианта:
1. специально сделанная ошибка,
2. китайцы, которые это написали - в работе это не проверяли. Либо проверяли, но для устройства с которым они работали было некритично наличие последнего NACK'a.
alux
Цитата(defunct @ Jul 19 2007, 18:18) *
Это оригинал? smile.gif
Тут только два варианта:
1. специально сделанная ошибка,
2. китайцы, которые это написали - в работе это не проверяли. Либо проверяли, но для устройства с которым они работали было некритично наличие последнего NACK'a.

Да, оригинал. Правильно ли будет с моей поправкой?
for(j=data_pack.size;((j)&&(state == SUCCESS));j--)
state = Get_byte(data_pack.data_ptr++,j);
Для разрабатываемого устройства важна надежность работы TWI. Сейчас думаю перейти на TWI с прерываниями (avr315). Есть ли там какие-нибудь подводные камни. И надежней ли так будет?
WHALE
я уже года 2 работаю с AVR315,глюков не замечал(кроме собственных :-))
alux
Если использовать avr315, как просто получить и/или принять один байт без применения буфера?
defunct
Цитата(alux @ Jul 20 2007, 14:53) *
Если использовать avr315, как просто получить и/или принять один байт без применения буфера?

Никак - буфер должен быть обязательно. И упр. структура.
Но это не должно Вас пугать. Это есть правильный подход.

Цитата(alux @ Jul 20 2007, 09:03) *
Правильно ли будет с моей поправкой?

Думаю что нет.
условие (j) равносильно (j > 0), вы используете пост декремент, а это значит, что 0 в теле цикла никогда не появится.

Я бы сделал функцию чтения блока, т.к. все равно побайтовый I2C обмен практически не нужен:
Код
U8 Get_Block( <Тип записи> *pDataPkt )
{
     U8 size = pDataPkt->size;
     U8 state = ACK;
     while( size-- &&  state == ACK)
     {
          state = Get_byte(pDataPkt->data_ptr++, size);
     }
     return state;
}
alux
Цитата(defunct @ Jul 20 2007, 15:10) *
условие (j) равносильно (j > 0), вы используете пост декремент, а это значит, что 0 в теле цикла никогда не появится.

Значит нужно сделать предекремент?

Цитата(defunct @ Jul 20 2007, 15:10) *
Я бы сделал функцию чтения блока...

Я бы предпочел использовать функцию Send_to_TWI , как в avr155. Только с поправкой (с предекрементом для receive data).

Как отправить по TWI (avr315) массив из 1000 байт? Не инициализировать же буфер из 1000 байт...
defunct
Цитата(alux @ Jul 20 2007, 18:13) *
Значит нужно сделать предекремент?

нет, нужно менять либо условие (т.к. проверка условия в цикле for делается до модификации),
либо параметр функции:
Get_Byte( xx, j - 1);

либо саму функцию..

Цитата
Я бы предпочел использовать функцию Send_to_TWI , как в avr155. Только с поправкой (с предекрементом для receive data).

я предпочитаю пользоваться функцией блочной записи/чтения:

/***********************************************
* i2c_MemTransfer() *
* begin interrupt handled transfer *
* ---> I2CAddr - address of the target device *
* if even - Master to slave direction *
* if odd - Slave to Master direction *
* ---> memAddr - address of memory cell *
* ---> count - number of bytes to transfer *
* ---> pData - data to write, or pointer to *
* buffer (if receiving) *
* <--- ничего не возвращает *
***********************************************/
void i2c_MemTransfer(U8 I2CAddr, U16 memAddr, U8 count, U8 *pData)

Цитата
Как отправить по TWI (avr315) массив из 1000 байт? Не инициализировать же буфер из 1000 байт...

Блоками например по 32 байта. И буфер сделать 32 байта.
Обычно объем буфера зависит от слейва.
Вы с каким устройством собираетесь работать через i2c?
alux
Цитата(defunct @ Jul 20 2007, 21:23) *
Вы с каким устройством собираетесь работать через i2c?

LCD(TIC154), DS1388(rtc), FOSP-01A(цифровой барометр)
Сейчас вот думаю , как отправить картинку (массив[1064] во флеше) в LCD.
Покажите, пожалуста, на примере с использованием аппаратного twi с прерываниями.
defunct
Цитата(alux @ Jul 20 2007, 21:30) *
Покажите, пожалуста, на примере с использованием аппаратного twi с прерываниями.

Рабочий пример под ARM. Надо будет поменять имена регистров на соответвующие из TWI модуля. Немного подрихтовать напильником, и можно использовать для AVR.

PS: I2C модуль ARM практически ничем (кроме имен регистров) не отличается от TWI модуля AVR
alux
я имел в виду пример кода, как отправить большой массив частями по 32 байта по аппаратному TWI. Ну да ладно. Наверно я изобретаю велосипед:
static const unsigned char __flash logo[]={....};
#define COUNT(logo) (sizeof(logo)/sizeof((logo)[0]))
const unsigned char __flash *pic;
unsigned int max;
unsigned char messageBuf[32];
pic = logo;
max=COUNT(logo);

for(unsigned int cnt = 0; cnt < (max/32); cnt++)
{
messageBuf[0] = (TWI_targetSlaveAddress<<TWI_ADR_BITS)|(FALSE<<TWI_READ_BIT);
for(unsigned char i=1;i<32;i++)
messageBuf[i] = *pic++;
TWI_Start_Transceiver_With_Data(messageBuf,32);
}
Только не понятно как быть, если размер массива не кратный 32? Т.е. последняя отправка неполного буфера.
...пока спрашивал, пришла мысль. Можно так?
messageBuf[0] = (TWI_targetSlaveAddress<<TWI_ADR_BITS)|(FALSE<<TWI_READ_BIT);
for(unsigned char i=1;i<(max%32);i++)
messageBuf[i] = *pic++;
TWI_Start_Transceiver_With_Data(messageBuf,(max%32));
...И еще. Первый элемент messageBuf всегда должен быть (TWI_targetSlaveAddress<<TWI_ADR_BITS)|(FALSE<<TWI_READ_BIT); в случае отправки.
Правильно ли я делаю?
defunct
Цитата(alux @ Jul 20 2007, 23:33) *
я имел в виду пример кода, как отправить большой массив частями по 32 байта по аппаратному TWI.

В рамках предыдущего примера - вызвать функцию I2C_TRANSFER n/32 раз с требуемыми параметрами в цикле... где n - объем данных в байтах который надо переслать..

Или Вам надо обязательно за одну транзакцию 1024 байта перегонять?

Цитата
Только не понятно как быть, если размер массива не кратный 32? Т.е. последняя отправка неполного буфера.

При отправке порции отнимайте 32 байта от суммарной длины. Когда остается меньше 32х байт, то отправляйте все что осталось и на этом собсно все.. Зачем там еще операции деления использовать?!
alux
Цитата(defunct @ Jul 21 2007, 00:15) *
При отправке порции отнимайте 32 байта от суммарной длины. Когда остается меньше 32х байт, то отправляйте все что осталось и на этом собсно все.. Зачем там еще операции деления использовать?!

Как узнать, что остается меньше 32х байт? А в моем варианте, допустим надо переслать 1064 байт. Первый раз отправляем 1064/32=33 раз. Остаток отправляем 1064%32=8 байт. А что Вас смущает?
defunct
Цитата(alux @ Jul 21 2007, 00:53) *
Как узнать, что остается меньше 32х байт? А в моем варианте, допустим надо переслать 1064 байт. Первый раз отправляем 1064/32=33 раз. Остаток отправляем 1064%32=8 байт. А что Вас смущает?


Код
while(size)
{
   BytesToSend = (size > 32) ? 32 : size;
   i2c_transfer( devaddr, memaddr, BytesToSend, pData);
   pData += BytesToSend;
   memaddr += BytesToSend;
   size -= BytesToSend;
}
alux
Вот, немного подрихтовал:
Код
static const unsigned char __flash logo[]={....};
#define COUNT(logo) (sizeof(logo)/sizeof((logo)[0]))
const unsigned char __flash *pic;
unsigned int size;
unsigned char messageBuf[32];
pic = logo;
size=COUNT(logo);
  while(size)
  {
    BytesToSend=(size > 32) ? 32 : size;
    for(unsigned char i=1;i<BytesToSend;i++)
    {
      messageBuf[0] = (TWI_targetSlaveAddress<<TWI_ADR_BITS)|(FALSE<<TWI_READ_BIT);
      messageBuf[i] = *pic++;
    }
    TWI_Start_Transceiver_With_Data(messageBuf,BytesToSend);
    size -= BytesToSend;
  }

Если имя массива использовать в качестве указателя на первый элемент, можно ли использовать его вместо указателя *pic? Т.е. написать *(logo++) вместо *pic++.
defunct
Цитата(alux @ Jul 21 2007, 20:51) *
Если имя массива использовать в качестве указателя на первый элемент, можно ли использовать его вместо указателя *pic? Т.е. написать *(logo++) вместо *pic++.

Массив нельзя ++ ...
Его можно только индексировать, либо так

logo[x]

либо так

*(<тип>)(logo + x);
ReAl
Цитата(alux @ Jul 21 2007, 20:51) *
Если имя массива использовать в качестве указателя на первый элемент, можно ли использовать его вместо указателя *pic? Т.е. написать *(logo++) вместо *pic++.
Нельзя. Имя logo - "константа", устанавливаемая линкером на этапе сборки проекта. Её можно использовать в выражениях, но её нельзя изменить.
alux
Не получается у меня загрузить картинку в индикатор с использованием аппаратного TWI с прерываниями (avr315). Хотя все работает, если формировать старт/стоп, отправку байта/адреса функционально, как в avr155. Прерывания после инициализации TWI разрешил. Что я не так делаю? Выкладываю код. В нем закоментированы участки кода, которые относятся к avr155.
Поделитесь опытом использования avr315.
alux
Цитата(defunct @ Jul 21 2007, 21:27) *
Массив нельзя ++ ...

Просматривал исходники на avrlib и наткнулся на запись "localBuffer[0]++;" , противоречащую Вашему утверждению. Это в функции i2cSlaveTransmitService. Что Вы скажете на это?
Сергей Борщ
Цитата(alux @ Jul 23 2007, 19:31) *
Что Вы скажете на это?
Что здесь инкрементируется не указатель на ячейку а содержимое ячейки localBuffer[0], что ничему не противоречит. Чтобы было понятнее - имя массива - константный указатель, т.е. указатель, который нельзя изменять. Можно завести обычный указатель, который будет указывать на тот же массив и уже его можно увеличивать/уменьшать:
Код
char Buffer[100]; // Buffer = имя масива, или (что то же самое) константный указатель на его нулевой элемент
void test(void)
{
   Buffer++;  // нельзя, Buffer - константный указатель
   char *pTmp;   // объявляем неконстантный указатель
   pTmp = Buffer; // pTmp указывает на нулевой элемент массива
   pTmp = &Buffer[0]; // то же самое

   pTmp = &Buffer[1]; //pTmp указывает на первый элемент массива
   pTmp = Buffer + 1;  // то же самое

   Buffer[0]++;   // увеличили на 1 первый элемент массива
   pTmp[0]++;   // то же самое
   *pTmp++;     // то же самое

   pTmp++;   // можно, pTmp - обычный указатель, увеличили указатель, теперь pTmp указывает на второй элемент.

   *(pTmp - 1)++;   // увеличили на 1 первый элемент массива

}
alux
Скажите, пожалуйста, стоит ли заморачиваться с аппаратным TWI с прерываниями (avr315) для управления LCD-индикатором TIC154 ? Если да, то покажите на примере. Например, необходимо произвести следующую последовательность :
START
Send(Address+W)
Send(N-bytes)
RESTART
Send(Address+W)
Send(M-bytes) //M=1064
STOP

Спасибо
defunct
Цитата(alux @ Jul 23 2007, 21:44) *
Если да, то покажите на примере.

А вы посмотрели тот пример, что я давал? Он 100% рабочий.
К сожалению портировать его на AVR смогу только на выходных, т.к. вся неделя загружена. Попробуйте перенести на AVR самостоятельно...

I2DAT ---> TWDR
I2STAT ---> TWSR
I2CON ---> TWCR

В остальном остается только обрабочик прерывания оформить, и настроить скорость TWI...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.