Перейти к содержанию
    

Atmega32/avrx/lm75a... При чтении второй байт = 255

Здравствуйте, может кто сталкивался. Есть 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, а вот какого оно там оказывается непонятно... Третий день бьюсь не могу победить...

Изменено пользователем zltigo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вчера ковырял даташиты на датчик... И заметил что первым должен передаваться msb, а только потом lsb

Получается у меня где-то в коде косяк, что TWDR читается не вовремя. Но блин уже раз 10 просмотрел и нигде косяков не вижу...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как же не люблю подобные начала постов

Нашел код для twi, подправил его слегка, запускаю...

С TWI вообще-то сами разобрались как он работает? Не было мысли, что в нем ошибка?

 

Страница 9 datasheet'а на LM75...Пункт 1.4...Таблица...

 

Где Вы увидели 2 байта для температуры?

Фактически 1 байт...

Второй для "полярности"...

 

Где Вы нашли

...(т.е. доли 0.125 градуса)...

Страница 11. Пункт 1.12

One LSB = 0.5˚C

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хотел грохнуть тему, но не смог... Потратил еще день и решил проблему. Код почти верный - ошибка как обычно из-за невнимательности. Я просто не заметил стадию 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/ Убрал этот кусок и все отлично заработало. Блин сколько раз говорил себе не брать чужой код - быстрее свой написать и каждый раз наступаю на эти грабли опять.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...