|
USI типа I2C на Tiny45, просто не работает |
|
|
|
Feb 22 2010, 19:39
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата Не получается прочитать байт от Тини, хоть тресни  А передать байт в тиню? Там же только запись, в моём примере. И это точно работало у меня  А другие устройства на i2c - перестали зависать? Возможно я не всё исправил, тогда надо ждать MTh, он это (неответ) вроде поборол.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Feb 22 2010, 19:52
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Ни привета, ни ответа. В слейве даже по условию Код if( USI_TWI_statusReg.dataInRxBuf ) { PORTB |= (1 << LED); ........ ничего не горит. Со стороны Меги вызываю Код void ReadSensor() { I2c_StartWait(SENSOR_ADDR | W); // slave address, write to sensor I2c_Write(TWI_CMD_MASTER_READ); I2c_RepStart(SENSOR_ADDR | R); // slave address + read bit, read sensor Value = (unsigned long)I2c_Read(I2C_ACK) << 24; Value |= (unsigned long)I2c_Read(I2C_ACK) << 16; Value |= (unsigned long)I2c_Read(I2C_ACK) << 8; Value |= (unsigned long)I2c_Read(I2C_NACK) << 0; I2c_Stop(); }
|
|
|
|
|
Feb 23 2010, 08:41
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Нашел одну ошибку: адрес слейв устройства в тини нужно инициализировать сдвинутым на 1 вправо. Т.е. из Меги передаю адрес 0х10, а в Тини TWI_SlaveAdress = 0x08. После этого начал зажигаться светодиод по условию, "буфер не пуст" и ЖКИ индикатор вроде как работает. "Вроде как" значит, что по включению питания на ЖКИ мусор и зависание, а после ресета по крайней мере проходит процедура инициализации ЖКИ. Но все-равно нет ответа от Тини  . Короче, в топку этот недоинтерфейс USI в режиме I2C. Буду пробовать трехпроводный SPI. Надеюсь, что с ним не будет таких проблем...
|
|
|
|
|
Feb 23 2010, 15:22
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(alux @ Feb 23 2010, 11:41)  Нашел одну ошибку... Разберитесь с адресацией (и с R\W заодно). Обычно предлагается два подхода. 1. Адрес отделяется от признака R\W; адрес - 7 бит. При приёме вы вручную выделяете сташие 7 бит принятого байта (сдвиг на 1 вправо, отбрасываем R\W) - это и будет адрес. При передаче сдвигаете адрес на 1 влево, добавляете R\W, и отправляете байт. Микросхема "пишется" и "читается" по одному и тому же адресу. В AVR312 именно так. Код проверки адреса: Код (( USIDR>>1 ) == TWI_slaveAddress 2. Адрес связан с R\W, микросхема "пишется" по одному адресу, а "читается" по другому; адрес - 8 бит. Обычно из двух этих адресов легко видно, что старшие 7 бит у них одинаковы, а младший бит адреса для "чтения" равен 1, - т.е. это просто R\W, и легко свести обмен к предыдущему подходу. Похоже, именно так у вас master реализован. Согласуйте подход в адресации, и должно завестись...
|
|
|
|
|
Feb 24 2010, 09:28
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(SysRq @ Feb 23 2010, 19:22)  Разберитесь с адресацией (и с R\W заодно). Повторю еще раз. Со стороны Меги : Код #define SENSOR_ADDR 0x10
I2c_StartWait(SENSOR_ADDR | W); // slave address, write to sensor I2c_Write(TWI_CMD_MASTER_READ); I2c_RepStart(SENSOR_ADDR | R); // slave address + read bit, read sensor Со стороны Тини: Код TWI_slaveAddress = 0x08; ............ case USI_SLAVE_CHECK_ADDRESS: if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) ) { if ( USIDR & 0x01 ) { overflowState = USI_SLAVE_SEND_DATA; } else { overflowState = USI_SLAVE_REQUEST_DATA; } SET_USI_TO_SEND_ACK( ); } ....... И где я не прав?
|
|
|
|
|
Feb 25 2010, 13:53
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Попробовал использовать USI (Tiny45) в режиме SPI (Slave). Все нормально запустилось. Отправляю от Тини число, на Меге это число принимаю и вывожу на ЖКИ. Но теперь необходимо поменять устройства ролями: Тини должен быть мастером, а Мега - подчиненным. Соответственно на Тини USCK настроил на выход, а у Меги, соответственно SCK, на вход. Кроме этого на Меге вывод SS настроен на вход и притянут перемычкой на землю. Функция передачи байта от Тини: Код unsigned char send_byte(unsigned char val) { USIDR = val; USISR = (1<<USIOIF); do { USICR = (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC); } while ((USISR & (1<<USIOIF)) == 0); return USIDR; }
void main() { SETBIT(DDRB, USCK); SETBIT(PORTB, USCK); SETBIT(DDRB, DO); CLRBIT(PORTB, DO); CLRBIT(DDRB, DI); SETBIT(PORTB, DI); for(;;) { SendByte(0x11); delay_ms(100); } } На Меге функция инициализации аппаратного SPI: Код // select clock phase negative-going in middle of data SPCR |= (1 << CPOL0); // data is sampled on the trailing (last) edge of SCK. SPI Mode - 3 SPCR |= (1 << CPHA0); // Data order MSB first SPCR &= ~(1 << DORD0); // enable SPI SPCR |= (1 << SPE0); // clear status SPSR = SPSR; SpiTransferComplete = true;
// enable SPI interrupt #ifdef SPI_USEINT SPCR |= (1 << SPIE0); #endif } В результате получаю число 255!!! Пробовал для Тини использовать программный SPI: Код void SendByte(unsigned char Data) { unsigned char BitCount = 8;
do { // Send bit to Slave, MSB first if(Data & 0x80) { SETBIT(PORTB, DO); } else { CLRBIT(PORTB, DO); } // Toggle SCK pin to send current bit CLRBIT(PORTB, USCK); SETBIT(PORTB, USCK); // Get next bit to send Data <<= 1; } while(--BitCount);
} Результат - тот же. В чем может быть проблема? Уже все перепробовал
|
|
|
|
|
Feb 26 2010, 22:57
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(alux @ Feb 24 2010, 12:28)  И где я не прав? Да не красиво как-то -- Цитата(alux @ Feb 25 2010, 16:53)  Код // clear status SPSR = SPSR; Так SPIF не сбросится, он read only. Сброс: Цитата SPIF is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, the SPIF bit is cleared by first reading the SPI Status Register with SPIF set, then accessing the SPI Data Register (SPDR).
|
|
|
|
|
Feb 27 2010, 14:39
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
SPIF = SPIF; в данном случае ни при чем. Проблема в том, что со стороны Меги MISO и MOSI перепутаны местами... Сбило с толку то, что когда Мега был Мастером, а Тини Слейвом, то все работало. Теперь, ничего не меняя в проводах, изменив только статусы мастера и слейва местами, и, соответственно, бит MSTR => 0 у Меги, MOSI у Меги должен быть входом, а MISO, соответственно, выходом!
PS. А вообще, логично было бы назвать вывод MISO - DI , MOSI - DO у Тини. Чем руководствовались Атмел, не понятно...
|
|
|
|
|
Feb 28 2010, 10:00
|
Местный
  
Группа: Свой
Сообщений: 256
Регистрация: 6-03-06
Из: Украина, г. Винница
Пользователь №: 15 017

|
Цитата А вообще, логично было бы назвать вывод MISO - DI , MOSI - DO у Тини. Чем руководствовались Атмел, не понятно... Возможно, Вы будете удивлены, но они почти так у Атмела и названы (с точностью до наоборот). У тини названия выводов MISO и MOSI никак не связаны с USI. Эти названия касаются только назначения ног в режиме программирования.
|
|
|
|
|
Mar 1 2010, 06:34
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
С USI(SPI) работает, но нужно организовывать протокол передачи байт, либо синхронизировать начало передачи выводом SS. А у Тини у меня уже нет лишних выводов. Вернулся я все-таки к интерфейсу USI->TWI(Slave). Обнаружил у себя одну ошибку настройки портов. Но все-равно драйвер USI->TWI(Slave) avr312 не работает, а вот этот исходник - работает.
|
|
|
|
|
Mar 2 2010, 09:23
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Чтобы отправить от Slave(Tiny45) длинный байт Код for(;;) { if(usiTwiSlave.available()) { //usiTwiSlave.receive();
usiTwiSlave.write((unsigned char)(Value >> 24)); usiTwiSlave.write((unsigned char)(Value >> 16)); usiTwiSlave.write((unsigned char)(Value >> 8)); usiTwiSlave.write((unsigned char)(Value >> 0)); } } в Master(Мега) нужно добавить задержки Код void ReadSensor() { I2c_StartWait(SENSOR_ADDR | W); // slave address, write to capsensor SENSOR_ADDR I2c_Write(TWI_CMD_MASTER_READ); I2c_RepStart(SENSOR_ADDR | R); // slave address + read bit, read capsensor SENSOR_ADDR ValueOfCharge = (unsigned long)I2c_Read(I2C_ACK) << 24; delay_ms(100); ValueOfCharge |= (unsigned long)I2c_Read(I2C_ACK) << 16; delay_ms(100); ValueOfCharge |= (unsigned long)I2c_Read(I2C_ACK) << 8; delay_ms(100); ValueOfCharge |= (unsigned long)I2c_Read(I2C_NACK) << 0; I2c_Stop(); } Тини работает от 8МГц, Мега - на 20 МГц. При меньших задержках - не работает.
|
|
|
|
|
Apr 1 2010, 11:15
|

Участник

Группа: Участник
Сообщений: 23
Регистрация: 1-07-09
Пользователь №: 50 799

|
код для принимающего утройтва принимает 6 байт ну еще широковещательный пакет обрабатываеться рабоатет по прерываниям CODE .include "tn45def.inc"
.def temp =r16 .def USIcnt =r19 .def USIstate =r20
.org 0 RJMP reset;RESET External Pin, Power-on Reset, Brown-out RJMP reset;INT0 External Interrupt Request 0 RJMP reset;PCINT0 External Interrupt Request 1 RJMP reset;TIMER1 COMPA Timer/Counter1 Compare Match A RJMP reset;TIMER1 OVF Timer/Counter1 Overflow RJMP reset;TIMER0 OVF Timer/Counter0 Overflow RJMP reset;EE_RDY EEPROM Ready RJMP reset;ANA_COMP Analog Comparator RJMP reset;ADC ADC Conversion Complete RJMP reset;TIMER1 COMPB Timer/Counter1 Compare Match B RJMP reset;TIMER0 COMPA Timer/Counter0 Compare Match A RJMP reset;TIMER0 COMPB Timer/Counter0 Compare Match B RJMP reset;WDT RJMP USIstart;USI - start RJMP USIofl;USI - Overflow ;----------------------- USIstart: push temp
ldi temp,1 mov USIstate,temp
in temp,USICR;(Enable USI Counter overflow interrupt) sbr temp,0b01000000 out USICR,temp rcall ClearACK pop temp reti
USIofl: push temp
mov temp,USIstate cpi temp,1 breq I2Cadr cpi temp,2 breq I2Cack cpi temp,3 breq I2Cbyte
rjmp USIend
I2Cadr: in temp,USIDR cpi temp,0b11111110 breq I2Calladr cpi temp,0b00000100 brne I2Cbadadr
; cbi portb,1
ldi xl,low(0x80);Set pointer on the first received byte ldi xh,high(0x80);адрес буфера дл япримеа
rcall SetACK
ldi temp,2 mov USIstate,temp clr USIcnt rjmp USIend
I2Cack: rcall ClearACK
inc USIcnt mov temp,USIcnt cpi temp,6; сколько приянть байтов breq I2Call
ldi temp,3 mov USIstate,temp rjmp USIend
I2Cbyte:
in temp,USIDR st X+,temp; прияняли очередной байт rcall SetACK
ldi temp,2 mov USIstate,temp rjmp USIend
I2Calladr: ; пришел шыроковещательный пакет
rjmp I2Cbadadr I2Call: ; sbi portb,1 ; прияны все данные!
I2Cbadadr: rcall StopDetected
USIend: pop temp reti ;-------- SetACK: sbi DDRB,0 sbi PortB,2 sbi DDRB,2
in temp,USISR cbr temp,0b00000001;(Set counter to 0xE) sbr temp,0b11101110;(Enable new interrupts. Releasing SCL) out USISR,temp ret
StopDetected:
in temp,USICR;(Disable USI Counter overflow interrupt) cbr temp,0b01000000 out USICR,temp
ClearACK:
cbi DDRB,0 cbi PortB,2 cbi DDRB,2
in temp,USISR cbr temp,0b00001111;(Clear counter) sbr temp,0b11100000;(Enable new interrupts. Releasing SCL) out USISR,temp ret ;------------------ reset:
ldi temp,high(RAMEND);High byte only required if out SPH,temp ;RAM is bigger than 256 Bytes ldi temp,low(RAMEND) out SPL,temp
ldi temp,0b00000010 out PORTB,temp ldi temp,0b00000010 out DDRB,temp
ldi temp,(1<<USISIE)+(1<<USIWM1)+(1<<USIWM0)+(1<<USICS1) out USICR,temp ldi temp,0xf0 out USISR,temp
ldi Zh,HIGH(reset) ldi Zl,LOW(reset)
ldi temp, 0b00100000 out MCUCR,temp
sei
clr USIstate
loop: sleep rjmp loop
Сообщение отредактировал IgorKossak - Apr 1 2010, 16:38
Причина редактирования: Неправильное оформление длинного текста
--------------------
|
|
|
|
|
Jan 24 2013, 11:31
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 21-09-11
Пользователь №: 67 320

|
Скажите, а примера реализации похожей задачи на ассемблере кто-нибудь видел? Цитата(Nuts_ @ Apr 1 2010, 15:15)  код для принимающего утройтва А кода для передающего устройства, того же Atiny45 ни у кого нету?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|