Написал простенькую программку, которая перебирает все возможные адреса TWI устройств на шине, если находит, выплёвывает адрес в COM. Сижу уже несколько дней и не понимаю в чем может быть проблема. Стартовый бит отправляется без проблем (я вижу сообщение "START bit transmitted"). Проблема начинается когда мы заходим в функцию write_byte(...). Там почему-то после записи регистров TWDR и TWCR не устанавливается флаг TWINT, и соответственно он зацикливается в while и спамит мне "Wait sending adress byte". Проверил, TWDR и TWCR записываются корректно. Пробовал выставлять задержки (хотя они тут не нужны), тоже ничего. Вообщем много что перепробовал. Дебажил всё в ардуино, потому что проще.
Код:
#include <Arduino.h>
//Set your needed setttings here
long int CPU_freq = 16000000; //Processor frequency of the microcontroller
long int FreqI2C = 200000; //Frequency of SCL line "Hz" (The frequency of operation of your connected device)
uint16_t twps_reg = 0x00; //TWI prescaler bits
//(TWPS = 0x00: freq SCL [30;10^3]KHz)
//(TWPS = 0x01: freq SCL [8;10^3]KHz)
//(TWPS = 0x02: freq SCL [2;10^3]KHz)
//(TWPS = 0x03: freq SCL [0.5;10^3]KHz)
//Global Variables
volatile uint8_t TWSR_state;
bool write = 0;
bool read = 1;
volatile uint8_t addres_device;
//All functions
//Initialization of bus I2C
void init_TWI(){
int Prescaler; //TWI Prescaler Bits (see Datasheet)
switch(twps_reg){
case 0x00: Prescaler = 1; break;
case 0x01: Prescaler = 4; break;
case 0x02: Prescaler = 16; break;
case 0x03: Prescaler = 64; break;
default: Serial.println("Check if the register twps_reg is correct");
Prescaler = 1; //default
}
TWBR = (CPU_freq/FreqI2C - 8)/Prescaler; //TWI Bit Rate Register
TWSR = twps_reg;
digitalWrite(SDA, 1); //Transfer the SCL and SDA lines to an internal pull-up resistor
digitalWrite(SCL, 1);
}
//Sending start bit
bool transfer_start_bit(){
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE); //TWI Control Register
while (!(TWCR & (1<<TWINT))) Serial.println("Wait sending START bit"); //Waiting for the TWINT bit to be set
if ((TWSR_state == 0x08) || (TWSR_state == 0x10)) return 1;
return 0;
}
//Sending SLA+W and data byte
bool write_byte(uint8_t byte, bool R_W){
TWDR = (byte << 1) + R_W; //TWI Data Register
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE);
while (!(TWCR & (1<<TWINT))) Serial.println("Wait sending address byte"); //Waiting for the TWINT bit to be set
if ((TWSR_state == 0x18) || (TWSR_state == 0x28)) return 1;
return 0;
}
//Sending STOP bit
void bus_stop(){
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO);
}
//Finding the adress of slave
uint8_t searching_I2C_device(){ //We are going through all possible addresses
for (uint8_t adress = 0x00; adress < 0xFF; adress++){
if (transfer_start_bit() == 1){
if (write_byte(adress, write) == 1) return adress;
}
bus_stop();
}
return 0;
}
//Timer1_delay
void time1_delay(int delay){ //Delay is specified in the number of processor cycles
TCCR1A = 0x00;
TCNT1 = 0x0000;
TCCR1B = (1<<WGM12)|(0<<CS12)|(1<<CS10)|(0<<CS11);
OCR1A = delay;
TIMSK1 = (1<<OCIE1A);
while(TIMSK1 & (1<<OCIE1A)){}
}
//Read status of TWSR register
ISR (TWI_vect){
switch(TWSR & 0xF8){
case 0x00: TWSR_state = 0x00; //Bus error due to an illegal START or STOP condition
Serial.println("Bus error due START or STOP condition");
break;
//bus_stop();
case 0x08: TWSR_state = 0x08; //A START condition has been tranmitted
Serial.println("START bit transmitted");
break;
case 0x10: TWSR_state = 0x10; //A repeated START condition has been transmitted
Serial.println("Reapeated START bit transmitted");
break;
case 0x18: TWSR_state = 0x18; //SLA+W has been transmitted and ACK has been recieved
Serial.println("SLA+W transmitted and ACK bit received");
break;
case 0x20: TWSR_state = 0x20; //SLA+W has been transmitted and NOT ACK has been recieved
Serial.println("SLA+W transmitted and NOT ACK bit received");
break;
//bus_stop();
case 0x28: TWSR_state = 0x28; //Data byte has been transmitted and ACK has been recieved
Serial.println("Data byte transmitted and ACK bit recieved");
break;
case 0x30: TWSR_state = 0x30; //Data byte has been transmitted and NOT ACK has been recieved
Serial.println("Data byte transmitted and NOT ACK bit recieved");
break;
bus_stop();
case 0xF8: TWSR_state = 0xF8; //No relevant state information available; TWINT = '0'
Serial.println("No relevant state information");
break;
default: TWSR_state = 0xFF; //Nothing of the above
Serial.println("Undefined state 0xFF");
break;
}
TWCR = 0x00;
}
//Turn off the Timer1
ISR(TIMER1_COMPA_vect){
cli();
TIMSK1 = (0<<OCIE1A);
asm volatile ("nop");
sei();
}
//Setup initial parameters
void setup() {
sei();
Serial.begin(9600);
Serial.println("Start finding the adress of VEML6040");
init_TWI();
}
void loop() {
addres_device = searching_I2C_device();
if(addres_device != 0){
Serial.print("Address of slave is 0x");
Serial.println(searching_I2C_device(), HEX);
}
else Serial.println("Address of device is not found");
bus_stop();
}