Bubi_00
21.03.2007, 09:44
Hallo Leute
Ich hab hier eine fertige Software von mikrocontroller.net für die USI vom ATTiny26 für einen I²C Slave.
http://www.mikrocontroller.net/topic/38917#287918
Danke an dieser Stelle, falls er es liest :)
Der Slave scheint einwandfrei zu funktionieren wenn ich nur 1nen Attiny am Bus habe.
Gebe ich aber einen zweiten Tiny hinzu Addressen (0xA0, 0xB0) hab ich das Problem, das mir auf eine Anfrage auf Addresse 0xA0, BEIDE antworten...
Genauso auch umgekehrt, er ignoriert also die Addresse...
#ifndef _I2C_SLAVE_C_
#define _I2C_SLAVE_C_
#include <avr/io.h>
#include <avr/interrupt.h>
#include "i2c_slave.h"
#define USI_DATA USIDR
#define USI_STATUS USISR
#define USI_CONTROL USICR
//Standart Device Address
#define NONE 0
#define ACK_PR_RX 1
#define BYTE_RX 2
#define ACK_PR_TX 3
#define PR_ACK_TX 4
#define BYTE_TX 5
// Device dependant defines
#define DDR_USI DDRB
#define PORT_USI PORTB
#define PIN_USI PINB
#define PORT_USI_SDA PORTB0
#define PORT_USI_SCL PORTB2
#define NONE 0
volatile unsigned char USI_address = NONE;
volatile uint8_t COMM_STATUS = NONE;
volatile unsigned char send_usi = NONE;
void USI_set(unsigned char data)
{
send_usi = data ;
}
void USI_init(unsigned char address) {
// Set the Device Address for the Slave Address+1 = Address with Reading
USI_address = address;
// 2-wire mode; Hold SCL on start and overflow; ext. clock
USI_CONTROL |= (1<<USIWM1) | (1<<USICS1);
USI_STATUS = 0xf0; // write 1 to clear flags, clear counter
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
DDR_USI |= (1<<PORT_USI_SCL);
PORT_USI |= (1<<PORT_USI_SCL);
// startcondition interrupt enable
USI_CONTROL |= (1<<USISIE);
}
ISR(USI_STRT_vect) {
uint8_t tmpUSI_STATUS;
tmpUSI_STATUS = USI_STATUS;
COMM_STATUS = NONE;
// Wait for SCL to go low to ensure the "Start Condition" has completed.
// otherwise the counter will count the transition
while ( (PIN_USI & (1<<PORT_USI_SCL)) );
USI_STATUS = 0xf0; // write 1 to clear flags; clear counter
// enable USI interrupt on overflow; SCL goes low on overflow
USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0);
}
ISR(USI_OVF_vect) {
uint8_t BUF_USI_DATA = USI_DATA;
switch(COMM_STATUS) {
case NONE:
if (((BUF_USI_DATA & 0xfe)) != USI_address & 0xfe) { // if not receiving my address
// disable USI interrupt on overflow; disable SCL low on overflow
USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0));
}
else { // else address is mine
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
if (BUF_USI_DATA & 0x01) COMM_STATUS = ACK_PR_TX; else COMM_STATUS = ACK_PR_RX;
}
break;
case ACK_PR_RX:
DDR_USI &= ~(1<<PORT_USI_SDA);
COMM_STATUS = BYTE_RX;
break;
case BYTE_RX:
/* Save received byte here! ... = USI_DATA*/
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = ACK_PR_RX;
break;
case ACK_PR_TX:
/* Put first byte to transmit in buffer here! USI_DATA = ... */
USI_DATA = send_usi;
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
COMM_STATUS = BYTE_TX;
break;
case PR_ACK_TX:
if(BUF_USI_DATA & 0x01) {
COMM_STATUS = NONE; // no ACK from master --> no more bytes to send
}
else {
/* Put next byte to transmit in buffer here! USI_DATA = ... */
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
DDR_USI |= (1<<PORT_USI_SDA);
COMM_STATUS = BYTE_TX;
}
break;
case BYTE_TX:
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = PR_ACK_TX;
break;
}
USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL
}
#endif
Bis auf ein paar Kleinigkeiten wurde am Code eigentlich nichts geändert. Sieht wer den Fehler?
mfg
Ich hab hier eine fertige Software von mikrocontroller.net für die USI vom ATTiny26 für einen I²C Slave.
http://www.mikrocontroller.net/topic/38917#287918
Danke an dieser Stelle, falls er es liest :)
Der Slave scheint einwandfrei zu funktionieren wenn ich nur 1nen Attiny am Bus habe.
Gebe ich aber einen zweiten Tiny hinzu Addressen (0xA0, 0xB0) hab ich das Problem, das mir auf eine Anfrage auf Addresse 0xA0, BEIDE antworten...
Genauso auch umgekehrt, er ignoriert also die Addresse...
#ifndef _I2C_SLAVE_C_
#define _I2C_SLAVE_C_
#include <avr/io.h>
#include <avr/interrupt.h>
#include "i2c_slave.h"
#define USI_DATA USIDR
#define USI_STATUS USISR
#define USI_CONTROL USICR
//Standart Device Address
#define NONE 0
#define ACK_PR_RX 1
#define BYTE_RX 2
#define ACK_PR_TX 3
#define PR_ACK_TX 4
#define BYTE_TX 5
// Device dependant defines
#define DDR_USI DDRB
#define PORT_USI PORTB
#define PIN_USI PINB
#define PORT_USI_SDA PORTB0
#define PORT_USI_SCL PORTB2
#define NONE 0
volatile unsigned char USI_address = NONE;
volatile uint8_t COMM_STATUS = NONE;
volatile unsigned char send_usi = NONE;
void USI_set(unsigned char data)
{
send_usi = data ;
}
void USI_init(unsigned char address) {
// Set the Device Address for the Slave Address+1 = Address with Reading
USI_address = address;
// 2-wire mode; Hold SCL on start and overflow; ext. clock
USI_CONTROL |= (1<<USIWM1) | (1<<USICS1);
USI_STATUS = 0xf0; // write 1 to clear flags, clear counter
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
DDR_USI |= (1<<PORT_USI_SCL);
PORT_USI |= (1<<PORT_USI_SCL);
// startcondition interrupt enable
USI_CONTROL |= (1<<USISIE);
}
ISR(USI_STRT_vect) {
uint8_t tmpUSI_STATUS;
tmpUSI_STATUS = USI_STATUS;
COMM_STATUS = NONE;
// Wait for SCL to go low to ensure the "Start Condition" has completed.
// otherwise the counter will count the transition
while ( (PIN_USI & (1<<PORT_USI_SCL)) );
USI_STATUS = 0xf0; // write 1 to clear flags; clear counter
// enable USI interrupt on overflow; SCL goes low on overflow
USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0);
}
ISR(USI_OVF_vect) {
uint8_t BUF_USI_DATA = USI_DATA;
switch(COMM_STATUS) {
case NONE:
if (((BUF_USI_DATA & 0xfe)) != USI_address & 0xfe) { // if not receiving my address
// disable USI interrupt on overflow; disable SCL low on overflow
USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0));
}
else { // else address is mine
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
if (BUF_USI_DATA & 0x01) COMM_STATUS = ACK_PR_TX; else COMM_STATUS = ACK_PR_RX;
}
break;
case ACK_PR_RX:
DDR_USI &= ~(1<<PORT_USI_SDA);
COMM_STATUS = BYTE_RX;
break;
case BYTE_RX:
/* Save received byte here! ... = USI_DATA*/
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = ACK_PR_RX;
break;
case ACK_PR_TX:
/* Put first byte to transmit in buffer here! USI_DATA = ... */
USI_DATA = send_usi;
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
COMM_STATUS = BYTE_TX;
break;
case PR_ACK_TX:
if(BUF_USI_DATA & 0x01) {
COMM_STATUS = NONE; // no ACK from master --> no more bytes to send
}
else {
/* Put next byte to transmit in buffer here! USI_DATA = ... */
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
DDR_USI |= (1<<PORT_USI_SDA);
COMM_STATUS = BYTE_TX;
}
break;
case BYTE_TX:
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = PR_ACK_TX;
break;
}
USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL
}
#endif
Bis auf ein paar Kleinigkeiten wurde am Code eigentlich nichts geändert. Sieht wer den Fehler?
mfg