Не работает I2C (TWI) Master на Atmega644p

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

Не работает I2C (TWI) Master на Atmega644p

Сообщение wrgcpp » 02 ноя 2015, 00:15

Соединил Atmega644p по I2C с Ардуиной Мега, на которой прошит стандартный код примера I2C Slave Receiver (ну разве что адрес поменял) :
Код: Выделить всё
// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup()
{
  Wire.begin(0b00000100);                // join i2c bus
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
}


Мега644 работает на частоте 16МГц от внешнего кварца. В неё прошит такой код:
Код: Выделить всё
#define F_CPU 16000000UL  //1  MHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#include <stdio.h>
#include "def.h"
#include "utils.h"
//#include "uart.h"
//#include "timer.h"
#include "segment.h"


//адрес ведомого с которым хотим пообщаться
#define SLAVE_ADDR 0b00000100

//макрос адреса + бит чтения
#define SLA_R   (SLAVE_ADDR | 0b00000001)
//макрос адреса + бит записи
#define SLA_W   (SLAVE_ADDR & 0b11111110)

// отправка команды СТАРТ
uint8_t I2C_StartCondition(void)
{
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
    if((TWSR & 0xf8) != TW_START) {
        segment_write_num(3);
        return 1;
    }
    return 0;
}

// отправка СТОП
void I2C_StopCondition(void)
{
    TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}

// отправка адреса
uint8_t I2C_SendAddr(uint8_t addr)
{
    TWDR = addr;                    //загрузка значения в регистр данных
    TWCR = (1<<TWINT)|(1<<TWEN);    //начало передачи байта данных
    while (!(TWCR & (1<<TWINT)));   //ожидание установки бита TWIN
    if((TWSR& 0xf8) != TW_MT_SLA_ACK) {
        segment_write_num(4);
        return 1;
    }
    return 0;
}

//отправка байта
uint8_t I2C_SendByte(uint8_t c)
{
    TWDR = c;//загрузка значения в регистр данных
    TWCR = (1<<TWINT)|(1<<TWEN);//начаало передачи байта данных
    while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
    if((TWSR& 0xf8) != TW_MT_DATA_ACK) {
        segment_write_num(5);
        return 1;
    }
    return 0;
}

//инициализация I2C как передатчика
void I2C_Init (uint8_t value)
{
    TWBR = value;
}

void setup();

int main(void)           
{
    setup();
    _delay_ms(1000);
    I2C_Init(72);

    while(1) {
        if(I2C_StartCondition()) {
            goto wait;
        }
        if(I2C_SendAddr(SLA_W)) {
            goto wait;
        }
        if(I2C_SendByte(0x1)) {
            goto wait;
        }

wait:
        I2C_StopCondition();
        _delay_ms(1000);
    }

    while(1) {
        _delay_ms(1000);
    }

    return 0;
}

void setup()
{
    segment_init();
    sei();
}


Значение 72 для регистра TWBR взял из атмеловского аппноута 315 (см. скрин). Фунцкия segment_write_num(n) выводит свой аргумент на семисегментный индикатор для отладки. Валится всё на передаче адреса, после передачи адреса выполняется такой код
Код: Выделить всё
if((TWSR& 0xf8) != TW_MT_SLA_ACK) {
        segment_write_num(4);
        return 1;
    }

и выводит на индикатор цифру 4, т.е. ACK от ардуины не получен. Подключение проверял много раз, пробовал с разными подтягивающими резисторами - 2.2К, 4.7К, 10К, 22К, ничего не работает. Смотрел осциллографом, на линиях SDA и SCL что-то происходит, рассмотреть детальнее на моём осциллографе невозможно. Прошу помощи!
Вложения
2015-11-02-010759_927x469_scrot.png
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl

Re: Не работает I2C (TWI) Master на Atmega644p

Сообщение wrgcpp » 03 ноя 2015, 07:18

Проблема решена, она была в вычислении адреса slave
теперь это
Код: Выделить всё
#define SLAVE_ADDR 0b00000100
//макрос адреса + бит чтения
#define SLA_R   (SLAVE_ADDR | 0b00000001)
//макрос адреса + бит записи
#define SLA_W   (SLAVE_ADDR & 0b11111110)

заменено на это
Код: Выделить всё
#define SLAVE_ADDR 20
//макрос адреса + бит чтения
#define SLA_R   (TW_READ | (SLAVE_ADDR << 1))
//макрос адреса + бит записи
#define SLA_W   (TW_WRITE | (SLAVE_ADDR << 1))
Аватара пользователя
wrgcpp
 
Сообщения: 52
Зарегистрирован: 22 янв 2015, 01:43
Откуда: Нижний Тагил
прог. языки: C, C++, Tcl


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 8