Regressor 0 8 августа, 2010 Опубликовано 8 августа, 2010 (изменено) · Жалоба Здравствуйте, может кто сталкивался. Есть atmega32 с RTOS avrx, нужно брать данные с 4 lm75bim5. Нашел код для twi, подправил его слегка, запускаю... Данные с датчиков читаются, но при чтении температуры младший байт (где доли градуса) читается нормально (для lm75bim5 там либо 0 либо 0x80), а старший почему-то всегда = 255. Думал датчик глючный, поменял на lm75a и вижу младший байт меняется 0/20/40... (т.е. доли 0.125 градуса), а старший опять таки 255. Шина работает на 100кгц, контроллер на 10мгц, прескаллер=0, битрейт=42. Вот код: // globals used to manage the state of the TWI static TimerControlBlock twiTimer; static AVRX_MUTEX(mutexTWI); static volatile uint8_t *pCurData; // incremented for each databyte sent/received static volatile uint16_t iDataCount; // buffer size; decremented until reaches zero static volatile uint8_t iMode; // the mode we're in (send/receive) static volatile uint8_t iRemoteAddr; // the address of the remote TWI unit /* TWI interrupt */ volatile uint8_t status; AVRX_SIGINT(SIG_2WIRE_SERIAL) { IntProlog(); // process twi state changes status = TWSR & TWSR_STATUS_MASK; if (iMode == TWI_M_MODE_TRANSMIT) { switch (status) { case TWI_ST_MASTER_STARTOK: // arbitration succeeded, so send the address byte TWDR = TWI_SLA_W(iRemoteAddr); TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; break; case TWI_ST_MASTER_SLAW_ACK: // write the first databyte TWDR = *pCurData++; iDataCount--; TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; break; case TWI_ST_MASTER_SEND_DATA_ACK: case TWI_ST_MASTER_SEND_DATA_NACK: // if there's more data, send it. Otherwise, send STOP and // signal that we're done if (iDataCount > 0) { TWDR = *pCurData++; iDataCount--; TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; } else { iMode = TWI_MODE_IDLE; // send STOP TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); } break; case TWI_ST_MASTER_LOSTBUS: iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; case TWI_ST_MASTER_SLAW_NACK: default: // something happened, so signal we're done iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; } } else if (iMode == TWI_M_MODE_SENDADDR) { switch (status) { case TWI_ST_MASTER_STARTOK: // arbitration succeeded, so send the address byte TWDR = TWI_SLA_R(iRemoteAddr); TWCR = TWI_TWINT | TWI_TWEA | TWI_TWEN | TWI_TWIE; break; case TWI_ST_MASTER_SLAR_ACK: iMode = TWI_M_MODE_XFERSIZE; TWCR = TWI_TWINT | TWI_TWEA | TWI_TWEN | TWI_TWIE; break; case TWI_ST_MASTER_SLAR_NACK: iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; default: // something happened, so signal we're done iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; } } else if (iMode == TWI_M_MODE_XFERSIZE) { switch (status) { case TWI_ST_MASTER_RCVDATA_ACK: if (TWDR < iDataCount) iDataCount = TWDR; // ask for the next byte iMode = TWI_M_MODE_RECEIVE; TWCR = TWI_TWINT | TWI_TWEA | TWI_TWEN | TWI_TWIE; break; default: // something happened, so signal we're done iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEA | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; } } else if (iMode == TWI_M_MODE_RECEIVE) { // TWI_M_MODE_RECV_DATA switch (status) { case TWI_ST_MASTER_RCVDATA_ACK: case TWI_ST_MASTER_RCVDATA_NACK: // if there's room for more data, get it. // Otherwise, send STOP and signal that we're done if (iDataCount > 0) { *pCurData++ = TWDR; iDataCount--; } if (iDataCount > 1) { TWCR = TWI_TWINT | TWI_TWEA | TWI_TWEN | TWI_TWIE; } else if (iDataCount > 0) { // last byte coming, so don't acknowledge TWCR = TWI_TWINT | TWI_TWEN | TWI_TWIE; } else { iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); } break; default: // something happened, so signal we're done iMode = TWI_MODE_IDLE; TWCR = TWI_TWINT | TWI_TWSTO | TWI_TWEN | TWI_TWIE; AvrXIntSetSemaphore(&mutexTWI); break; } } Epilog(); } /* Initialize the TWI port for master mode */ void twiInitMaster(uint8_t prescale, uint8_t bitrate) { iMode = TWI_MODE_IDLE; // set the prescaler and the datarate register TWSR = prescale; TWBR = bitrate; TWCR = (0<<TWEN)| // Enable TWI-interface and release TWI pins. (0<<TWIE)|(0<<TWINT)| // Disable Interupt. (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // No Signal requests. (0<<TWWC); } /* Send bytes to a slave. Block caller until transfer is complete, or times out */ uint8_t twiMasterWrite(uint8_t addr, uint8_t *data, uint8_t datalen) { // don't preempt a transfer in progress if (iMode != TWI_MODE_IDLE) return 0; // queue up the data. // data is used in place, so it must remain stable while the transfer is in process AvrXResetSemaphore(&mutexTWI); pCurData = data; iDataCount = datalen; iRemoteAddr = addr; iMode = TWI_M_MODE_TRANSMIT; // send start TWCR = TWI_TWINT | TWI_TWSTA | TWI_TWEN | TWI_TWIE; AvrXWaitSemaphore(&mutexTWI); return datalen - iDataCount; } /* Receive bytes from a slave. Block caller until transfer is complete, or times out */ uint8_t twiMasterRead(uint8_t addr, uint8_t *data, uint8_t datalen) { // don't preempt a transfer in progress if (iMode != TWI_MODE_IDLE) return 0; // queue up the data. // data is used in place, so it must remain stable while the transfer is in process AvrXResetSemaphore(&mutexTWI); pCurData = data; iDataCount = datalen; iRemoteAddr = addr; iMode = TWI_M_MODE_SENDADDR; // send start TWCR = TWI_TWINT | TWI_TWSTA | TWI_TWEN | TWI_TWIE; AvrXWaitSemaphore(&mutexTWI); return pCurData - data; } int lm75_writeRegister(char i2c_addr, char reg_addr, unsigned char *dat, char len) { unsigned char tmp[len+1]; tmp[0] = reg_addr & 0x07; memcpy(&tmp[1], dat, len); if (twiMasterWrite(i2c_addr, tmp, len + 1) < len) return(-1); return 0; } int lm75_readRegister(char i2c_addr, char reg_addr, unsigned char *dst, char len) { unsigned char tmp; tmp = reg_addr & 0x07; if (twiMasterWrite(i2c_addr, &tmp, 1)) { if (twiMasterRead(i2c_addr, dst, len) < len) return(-1); } else return(-1); return(0); } int lm75_configure(char i2c_addr, unsigned char cfg) { return lm75_writeRegister(i2c_addr, LM75_REG_CFG, &cfg, 1); } В основном коде имеется задача: /* The task to read temperature sensors */ #define LM75_ADDR1 (LM75_ADDR_BASE + 0) // first sensor AVRX_GCC_TASKDEF(TSensorsTask, 64, 1) { int x = 0; unsigned char dst[2]; twiInitMaster(TWI_PRESCALER, TWI_BITRATE); if (lm75_configure(LM75_ADDR1, 0x60) != 0) printf_P(PSTR("LM75 configure error\r\n"));; while (1) { x = lm75_readRegister(LM75_ADDR1, LM75_REG_TEMP, &dst[0], 2); if (x==0) { printf_P(PSTR("Read sensor value: %X %X\r\n"), dst[0], dst[1]); } else { printf_P(PSTR("Read sensor value error\r\n")); } AvrXDelay(&timer2, 1000); // 1000 ms delay } } В итоге имею выход: Read sensor value: 40 FF Read sensor value: 20 FF Read sensor value: C0 FF Read sensor value: 0 FF Read sensor value: 0 FF Read sensor value: 0 FF Read sensor value: E0 FF Read sensor value: E0 FF Read sensor value: C0 FF Read sensor value: A0 FF Т.е. младший байт вроде адекватный, а старший не читается. Контроллер загружен на примерно 30% (avrx, 4 шима на 30кгц). Причем 0xFF берется именно из TWDR, а вот какого оно там оказывается непонятно... Третий день бьюсь не могу победить... Изменено 8 августа, 2010 пользователем zltigo Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Regressor 0 9 августа, 2010 Опубликовано 9 августа, 2010 · Жалоба Вчера ковырял даташиты на датчик... И заметил что первым должен передаваться msb, а только потом lsb Получается у меня где-то в коде косяк, что TWDR читается не вовремя. Но блин уже раз 10 просмотрел и нигде косяков не вижу... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mrKirill 1 11 августа, 2010 Опубликовано 11 августа, 2010 · Жалоба Как же не люблю подобные начала постов Нашел код для twi, подправил его слегка, запускаю... С TWI вообще-то сами разобрались как он работает? Не было мысли, что в нем ошибка? Страница 9 datasheet'а на LM75...Пункт 1.4...Таблица... Где Вы увидели 2 байта для температуры? Фактически 1 байт... Второй для "полярности"... Где Вы нашли ...(т.е. доли 0.125 градуса)... Страница 11. Пункт 1.12 One LSB = 0.5˚C Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Regressor 0 12 августа, 2010 Опубликовано 12 августа, 2010 · Жалоба Хотел грохнуть тему, но не смог... Потратил еще день и решил проблему. Код почти верный - ошибка как обычно из-за невнимательности. Я просто не заметил стадию iMode == TWI_M_MODE_XFERSIZE в чужом коде и в этом вся проблема. Теперь по пунктам. 1.Как тви работает - знаю, просто раньше на прерываниях с ним не работал. Так что "не люблю" наверное не в кассу. 2.Помимо LM75 еще имеется LM75A в даташите которого и написано про 0.125 градусов. В начале поста я об этом написал. 3.Температура в lm75 - 16 бит из которых в lm75 используется 9 бит, в lm75a 11 бит. В обоих случаях по twi надо получать 2 байта. 4.Проблема заключалась в том, что в этом коде, который я адаптировал к своим нуждам перед приемом данных принимался байт с размерами этих самых данных, а lm75 его не шлет. Соответственно в размер попадал MSB, в первый байт данных LSB, а во второй байт TWDR был уже неопределен - 0xFF/ Убрал этот кусок и все отлично заработало. Блин сколько раз говорил себе не брать чужой код - быстрее свой написать и каждый раз наступаю на эти грабли опять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться