Cette page vous affiche les différences entre la révision choisie et la version actuelle de la page.
robotics:computing:communication_twi_entre_atmega [2010/03/16 18:33] gdo |
robotics:computing:communication_twi_entre_atmega [2013/09/27 15:56] (Version actuelle) ldo [Master] |
||
---|---|---|---|
Ligne 25: | Ligne 25: | ||
====== Implémentation ====== | ====== Implémentation ====== | ||
===== Registres TWI ===== | ===== Registres TWI ===== | ||
- | TWCR contient tous les bits de controle de la communication : | + | == TWCR registre de controle== |
+ | Il contient tous les bits de controle de la communication : | ||
* TWINT : c'est le flag d'interruption | * TWINT : c'est le flag d'interruption | ||
* TWEA : ce bit permet d'activer l'envoie des bits d'acquittement. | * TWEA : ce bit permet d'activer l'envoie des bits d'acquittement. | ||
Ligne 33: | Ligne 34: | ||
* TWEN : Ce bit permet d'activer la communication TWI | * TWEN : Ce bit permet d'activer la communication TWI | ||
* TWIE : Ce bit permet d'activer les interruptions TWI. | * TWIE : Ce bit permet d'activer les interruptions TWI. | ||
- | TWAR contient l'adresse esclave | + | ==TWAR registre d'adresse == |
+ | Il contient l'adresse esclave | ||
* TWA6-TWA0 : Ces bits contiennent l'adresse esclave. | * TWA6-TWA0 : Ces bits contiennent l'adresse esclave. | ||
* TWGCE : Ce bit indique si l'esclave répond ou ignore la requête générale émise par un maitre. | * TWGCE : Ce bit indique si l'esclave répond ou ignore la requête générale émise par un maitre. | ||
- | TWDR contient l'octet reçu ou envoyé. | + | ==TWDR registre de données == |
- | TWSR est le registre de status | + | Il contient l'octet reçu ou envoyé. |
+ | ==TWSR registre de status== | ||
* TWS7-TWS3 : contient le code qui détermine l'état dans lequel se trouve la communication (adresse reçue ou donnée envoyée). | * TWS7-TWS3 : contient le code qui détermine l'état dans lequel se trouve la communication (adresse reçue ou donnée envoyée). | ||
* TWPS1-TWPS0 : contient le prescaler qui détermine la fréquence d'horloge SCL. | * TWPS1-TWPS0 : contient le prescaler qui détermine la fréquence d'horloge SCL. | ||
- | TWBR est le registre qui contient la valeur de la fréquence d'horloge SCL. | + | ==TWBR == |
- | FSCL = FCPU/(16+(2*TWBR*Prescaler)) | + | C'est le registre qui contient la valeur de la fréquence d'horloge SCL. |
+ | SCLfreq = CPUfreq/(16+(2*TWBR*Prescaler)) | ||
+ | |||
+ | Exemple : On travaille avec un ATMEGA cadencé à 16MHz et on souhaite une vitesse de 100Kz. | ||
+ | TWBR*Prescaler = (CPUfreq - 16 * SCLfreq)/(2*SCLfreq) = (16MHz - 16 * 100KHz) / (2 * 100 KHz) = 72 | ||
+ | Si on prend un prescaler de 1, on a TWBR = 72. | ||
===== Slave ===== | ===== Slave ===== | ||
L'implémentation de la communication twi sur l'esclave va utiliser les interruptions. A chaque fois que l'esclave va recevoir un octet, la routine d'interruption va être appelée. Dans cette routine, nous allons tester le registre TWSR qui va nous renseigner sur le type d'information qu'il vient de recevoir et pouvoir la traiter correctement. | L'implémentation de la communication twi sur l'esclave va utiliser les interruptions. A chaque fois que l'esclave va recevoir un octet, la routine d'interruption va être appelée. Dans cette routine, nous allons tester le registre TWSR qui va nous renseigner sur le type d'information qu'il vient de recevoir et pouvoir la traiter correctement. | ||
- | <code> | + | <code c> |
/* | /* | ||
- | * twislave.c | + | * twi_slave.c |
* | * | ||
* Created on: 26 févr. 2010 | * Created on: 26 févr. 2010 | ||
Ligne 53: | Ligne 61: | ||
*/ | */ | ||
- | /* ATMEGA48 @20MHz | + | volatile uint8_t twi_flag_read_complete = 1; |
- | * LOW FUSE : F7 | + | volatile uint8_t twi_flag_write_complete = 1; |
- | * CKDIV8=1 no divided clock by 8 | + | |
- | * CKOUT=1 no clock output on PORTB | + | |
- | * SUT1..0=11 slowly rising power | + | |
- | * CKSEL3..0=0111 full swing crystal oscillator | + | |
- | */ | + | |
- | #include <avr/interrupt.h> | + | volatile uint8_t *twi_receive_buffer; |
- | #include<util/twi.h> | + | volatile uint8_t *twi_transmit_buffer; |
+ | volatile uint8_t twi_i = 0; | ||
- | void twiSlaveInitialise(unsigned char myAddress); | + | uint8_t twi_nb_data_to_transmit; |
ISR(TWI_vect) | ISR(TWI_vect) | ||
{ | { | ||
- | switch (TWSR) | + | uint8_t status; |
- | { | + | |
- | /* Slave Transmitter*/ | + | |
- | case (TW_ST_SLA_ACK): /* 0xA8 : SLA+R received, ACK returned*/ | + | |
- | break; | + | |
- | case (TW_ST_ARB_LOST_SLA_ACK): /* 0xB0 : arbitration lost in SLA+RW, SLA+R received, ACK returned */ | + | |
- | break; | + | |
- | case (TW_ST_DATA_ACK): /* 0xB8 : data transmitted, ACK received */ | + | |
- | break; | + | |
- | case (TW_ST_DATA_NACK):/*0xC0 : data transmitted, NACK received */ | + | |
- | break; | + | |
- | case (TW_ST_LAST_DATA): /* 0xC8 : last data byte transmitted, ACK received */ | + | |
- | break; | + | |
- | /* Slave Receiver */ | + | status = TWSR & 0xF8; |
- | case (TW_SR_SLA_ACK):/* 0x60 : SLA+W received, ACK returned */ | + | switch (status) |
- | break; | + | { |
- | case (TW_SR_ARB_LOST_SLA_ACK):/*0x68 : arbitration lost in SLA+RW, SLA+W received, ACK returned */ | + | /* Slave Receiver */ |
- | break; | + | case (TW_SR_SLA_ACK):/* 0x60 : SLA+W received, ACK returned */ |
- | case (TW_SR_GCALL_ACK): /*0x70 : general call received, ACK returned */ | + | break; |
- | break; | + | case (TW_SR_ARB_LOST_SLA_ACK):/*0x68 : arbitration lost in SLA+RW, SLA+W received, ACK returned */ |
- | case (TW_SR_ARB_LOST_GCALL_ACK): /* 0x78 : arbitration lost in SLA+RW, general call received, ACK returned */ | + | break; |
- | break; | + | case (TW_SR_GCALL_ACK): /*0x70 : general call received, ACK returned */ |
- | case (TW_SR_DATA_ACK): /* 0x80 : data received, ACK returned */ | + | break; |
- | break; | + | case (TW_SR_ARB_LOST_GCALL_ACK): /* 0x78 : arbitration lost in SLA+RW, general call received, ACK returned */ |
- | case (TW_SR_DATA_NACK): /* 0x88 : data received, NACK returned */ | + | break; |
- | break; | + | case (TW_SR_DATA_ACK): /* 0x80 : data received, ACK returned */ |
- | case (TW_SR_GCALL_DATA_ACK): /* 0x90 : general call data received, ACK returned */ | + | twi_receive_buffer[0] = TWDR; |
- | break; | + | break; |
- | case (TW_SR_GCALL_DATA_NACK):/* 0x98 : general call data received, NACK returned */ | + | case (TW_SR_DATA_NACK): /* 0x88 : data received, NACK returned */ |
- | break; | + | break; |
- | case (TW_SR_STOP):/* 0xA0 : stop or repeated start condition received while selected */ | + | case (TW_SR_GCALL_DATA_ACK): /* 0x90 : general call data received, ACK returned */ |
- | break; | + | break; |
+ | case (TW_SR_GCALL_DATA_NACK):/* 0x98 : general call data received, NACK returned */ | ||
+ | break; | ||
+ | case (TW_SR_STOP):/* 0xA0 : stop or repeated start condition received while selected */ | ||
+ | twi_flag_write_complete = 1; | ||
+ | break; | ||
- | default: | + | /* Slave Transmitter */ |
- | break; | + | case (TW_ST_SLA_ACK): /* 0xA8 : SLA+R received, ACK returned*/ |
- | } | + | twi_i = 0; |
+ | TWDR = twi_transmit_buffer[twi_i]; | ||
+ | twi_i++; | ||
+ | break; | ||
+ | case (TW_ST_ARB_LOST_SLA_ACK): /* 0xB0 : arbitration lost in SLA+RW, SLA+R received, ACK returned */ | ||
+ | break; | ||
+ | case (TW_ST_DATA_ACK): /* 0xB8 : data transmitted, ACK received */ | ||
+ | TWDR = twi_transmit_buffer[twi_i]; | ||
+ | twi_i++; | ||
+ | break; | ||
+ | case (TW_ST_DATA_NACK):/*0xC0 : data transmitted, NACK received */ | ||
+ | break; | ||
+ | case (TW_ST_LAST_DATA): /* 0xC8 : last data byte transmitted, ACK received */ | ||
+ | break; | ||
- | TWCR = (1 << TWINT); // TWINT flag bit is cleared | + | default: |
+ | break; | ||
+ | } | ||
+ | |||
+ | TWCR |= (1 << TWINT); // TWINT flag bit is cleared | ||
} | } | ||
- | void twiSlaveInitialise(unsigned char myAddress) | + | /* TWI slave setup */ |
+ | void | ||
+ | twi_slave_setup(uint8_t address, volatile uint8_t * buffer, | ||
+ | volatile uint8_t *receive_buffer) | ||
{ | { | ||
- | PRR = (0 << PRTWI); // the PRTWI bit in PRR must be written to zero to enable the TWI | + | TWAR = (address << 1); // Set own TWI slave address. Accept TWI General Calls. |
- | TWAR = myAddress + 1; // Set own TWI slave address. Accept TWI General Calls. | + | twi_transmit_buffer = buffer; |
- | /* TWINT = 0 : | + | twi_receive_buffer = receive_buffer; |
- | * TWEA = 1 : enable ACK | + | TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); |
- | * TWSTA = 0: start condition | + | SREG |= (1 << SREG_I); |
- | * TWSTO = 0 : stop condition | + | |
- | * TWEN = 1 : enable the TWI | + | |
- | * TWIE = 1 : enable TWI interrupt */ | + | |
- | TWCR = (0 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 | + | |
- | << TWEN) | (1 << TWIE); | + | |
} | } | ||
- | int main(void) | + | volatile uint8_t tb[3], rb[3] ; |
+ | |||
+ | void | ||
+ | setup(void) | ||
{ | { | ||
- | twiSlaveInitialise(0x20); | + | DDRD = 0xFF; |
- | SREG = (1 << SREG_I); /* The Global Interrupt Enable bit must be set for the interrupts to be enabled */ | + | DDRC = 0x00; |
+ | twi_slave_setup(0x68, tb, rb); | ||
+ | } | ||
- | while (1) | + | int |
- | { | + | main(void) |
- | } | + | { |
- | return 1; | + | setup(); |
+ | |||
+ | while (1) | ||
+ | { | ||
+ | if (rb[0]==0x41) | ||
+ | { | ||
+ | tb[0] = 0x47; | ||
+ | tb[1] = 0x49; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | tb[0] = 0x27; | ||
+ | tb[1] = 0x29; | ||
+ | } | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
===== Master ===== | ===== Master ===== | ||
- | Ce code permet d'envoyer une donnée à un esclave | + | Ce code permet d'envoyer une donnée à un esclave. |
- | <code> | + | |
+ | Dans un premier temps, on va définir la vitesse de communication en initialisant TWBR et le prescaler dans twi_master_setup(). | ||
+ | <code c> | ||
/* | /* | ||
* twiMaster.c | * twiMaster.c | ||
Ligne 145: | Ligne 178: | ||
*/ | */ | ||
- | /* ATMEGA48 @20MHz | + | volatile uint8_t slave_address; |
- | * pull up resistor 1.5kohm | + | |
- | * LOW FUSE : F7 | + | |
- | * CKDIV8=1 no divided clock by 8 | + | |
- | * CKOUT=1 no clock output on PORTB | + | |
- | * SUT1..0=11 slowly rising power | + | |
- | * CKSEL3..0=0111 full swing crystal oscillator | + | |
- | */ | + | |
- | #include<util/twi.h> | + | volatile uint8_t twi_flag_read_complete = 1; |
+ | volatile uint8_t twi_flag_write_complete = 1; | ||
- | //sets bitrate and prescaler | + | volatile uint8_t *twi_receive_buffer; |
- | void twiMasterInitialise(unsigned char bitRate, unsigned char prescaler) | + | volatile uint8_t *twi_transmit_buffer; |
+ | volatile uint8_t twi_i = 0; | ||
+ | |||
+ | uint8_t twi_mode; | ||
+ | uint8_t twi_nb_data_to_transmit, twi_nb_data_to_receive; | ||
+ | |||
+ | ISR(TWI_vect) | ||
{ | { | ||
- | PRR = (0 << PRTWI); // the PRTWI bit in PRR must be written to zero to enable the TWI | + | uint8_t status; |
- | TWSR = prescaler & 0x03; | + | |
- | TWBR = bitRate; | + | status = TWSR & 0xF8; |
+ | switch (status) | ||
+ | { | ||
+ | case (TW_START): /* 0x08 : start condition transmitted */ | ||
+ | case (TW_REP_START): /* 0x10 : repeated START condition transmitted */ | ||
+ | twi_address(); | ||
+ | twi_i = 0; | ||
+ | break; | ||
+ | case (TW_MT_ARB_LOST): /* 0x38 : arbitration lost in SLA+RW, SLA+R received, ACK returned */ | ||
+ | break; | ||
+ | |||
+ | /* Master Transmitter */ | ||
+ | case (TW_MT_SLA_ACK): /* 0x18 : SLA+W transmitted; ACK received */ | ||
+ | case (TW_MT_SLA_NACK): /* 0x20 : SLA+W transmitted; NACK received */ | ||
+ | TWDR = twi_transmit_buffer[0]; | ||
+ | TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE) | (1 << TWINT); | ||
+ | twi_i++; | ||
+ | break; | ||
+ | |||
+ | case (TW_MT_DATA_ACK):/* 0x28 : data has been transmitted; ACK has been received */ | ||
+ | case (TW_MT_DATA_NACK): /* 0x30 : data has been transmitted; NACK has been received */ | ||
+ | if (twi_i == twi_nb_data_to_transmit) | ||
+ | { | ||
+ | if (twi_mode == WRITE) | ||
+ | { | ||
+ | twi_stop(); | ||
+ | twi_flag_write_complete = 1; | ||
+ | } | ||
+ | else // READ | ||
+ | { | ||
+ | slave_address++; | ||
+ | twi_start(); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | twi_data(twi_transmit_buffer[twi_i]); | ||
+ | twi_i++; | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | /* Master Receiver */ | ||
+ | case (TW_MR_SLA_ACK):/* 0x40 : SLA+R has been transmitted; ACK has been received */ | ||
+ | |||
+ | case (TW_MR_SLA_NACK): /* 0x48 : SLA+R has been transmitted; NACK has been received */ | ||
+ | if (twi_nb_data_to_receive == 1) | ||
+ | { | ||
+ | TWCR &= ~(1 << TWEA); /* desactiver ACK pour la derniere demande */ | ||
+ | } | ||
+ | break; | ||
+ | case (TW_MR_DATA_ACK):/* 0x50 : data received, ACK transmitted */ | ||
+ | case (TW_MR_DATA_NACK): /* 0x58 : data received, NACK transmitted */ | ||
+ | twi_receive_buffer[twi_i] = TWDR; | ||
+ | twi_i++; | ||
+ | |||
+ | if (twi_i == (twi_nb_data_to_receive - 1)) | ||
+ | { | ||
+ | TWCR &= ~(1 << TWEA); /* desactiver ACK pour la derniere demande */ | ||
+ | } | ||
+ | if (twi_i == twi_nb_data_to_receive) | ||
+ | { | ||
+ | twi_flag_read_complete = 1; | ||
+ | twi_stop(); | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | default: | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | TWCR |= (1 << TWINT); // TWINT flag bit is cleared | ||
} | } | ||
- | void twiError(void) | + | /* |
+ | * twi master setup | ||
+ | * SCLfreq = CPUfreq / (16 + 2 * TWBR * presc) | ||
+ | * */ | ||
+ | void | ||
+ | twi_master_setup(void) | ||
{ | { | ||
+ | PORTC = (1 << PC5) | (1 << PC4); // activate internal pull_ups for twi | ||
+ | TWSR = 0x00; // no prescaler | ||
+ | TWBR = 72; // 100kHz @16Mhz | ||
+ | //TWBR = 0x0C; // 400 KHz @16MHz | ||
+ | TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE) | (1 << TWINT); | ||
+ | SREG |= (1 << SREG_I); | ||
} | } | ||
- | void twiWait(unsigned char myStatus) | + | void |
+ | TWI_wait(void) | ||
{ | { | ||
- | while (!(TWCR & (1 << TWINT))) | + | while (!(TWCR & (1 << TWINT))) |
- | ; | + | ; |
- | if ((TWSR & 0xF8) != myStatus) | + | |
- | { | + | |
- | twiError(); | + | |
- | } | + | |
} | } | ||
- | /* send START condition bit */ | + | /* transmit START condition */ |
- | void twiStart(void) | + | void |
+ | twi_start(void) | ||
{ | { | ||
- | /* TWINT : TWI interrupt flag | + | TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWSTA); /* send start condition */ |
- | * TWSTA : TWI START condition bit | + | |
- | * TWSTO : TWI STOP condition bit | + | |
- | * TWEN : TWI enable bit */ | + | |
- | TWCR = (1 << TWINT) | (1 << TWSTA) | (0 << TWSTO) | (1 << TWEN); | + | |
- | twiWait(TW_START); | + | |
} | } | ||
- | /* send slave address */ | + | /* transmit slave address SLA */ |
- | void twiAddress(unsigned char myAddress) | + | void |
+ | twi_address(void) | ||
{ | { | ||
- | TWDR = myAddress; | + | TWDR = slave_address; /* load SLA into TWDR */ |
- | TWCR = (1 << TWINT) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN); | + | |
- | twiWait(TW_MT_SLA_ACK); // 0x18, 0x20 or 0x38 | + | TWCR &= ~(1 << TWSTA); /* desactivate START */ |
} | } | ||
- | /* send data */ | + | /* transmit data */ |
- | void twiData(unsigned char myData) | + | void |
+ | twi_data(uint8_t data) | ||
{ | { | ||
- | TWDR = myData; | + | TWDR = data; |
- | TWCR = (1 << TWINT) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN); | + | |
- | twiWait(TW_MT_DATA_ACK); | + | |
} | } | ||
- | /* send STOP condition bit */ | + | /* transmit STOP condition */ |
- | void twiStop(void) | + | void |
+ | twi_stop(void) | ||
{ | { | ||
- | TWCR = (1 << TWINT) | (0 << TWSTA) | (1 << TWSTO) | (1 << TWEN); | + | TWCR |= (1 << TWSTO); /* STOP */ |
} | } | ||
- | /* write data to slaveAddress */ | + | void |
- | void twiWriteData(unsigned char slaveAddress, unsigned char data) | + | twi_write_bytes(uint8_t add, uint8_t nb_bytes, volatile uint8_t *buffer) |
{ | { | ||
- | twiStart(); | + | if (twi_flag_write_complete == 1) |
- | twiAddress(slaveAddress); | + | { |
- | twiData(data); | + | twi_flag_write_complete = 0; |
- | twiStop(); | + | slave_address = add << 1; |
+ | twi_transmit_buffer = buffer; | ||
+ | twi_start(); | ||
+ | } | ||
} | } | ||
+ | void | ||
+ | twi_read_bytes(uint8_t add, volatile uint8_t *reg, uint8_t nb_bytes, | ||
+ | volatile uint8_t *buffer) | ||
+ | { | ||
+ | if (twi_flag_read_complete == 1) | ||
+ | { | ||
+ | twi_flag_read_complete = 0; | ||
+ | twi_flag_write_complete = 0; | ||
- | int main(void) | + | slave_address = add; |
+ | |||
+ | twi_transmit_buffer = reg; | ||
+ | |||
+ | twi_mode = READ; | ||
+ | twi_nb_data_to_transmit = 1; | ||
+ | twi_nb_data_to_receive = nb_bytes; | ||
+ | |||
+ | twi_receive_buffer = buffer; | ||
+ | |||
+ | twi_start(); | ||
+ | while (twi_flag_read_complete == 0) | ||
+ | ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void | ||
+ | setup(void) | ||
{ | { | ||
- | twiMasterInitialise(92, 0); //set TWBR = 92 for 100kHz SCL @ 20MHz | + | twi_master_setup(); |
+ | } | ||
- | while (1) | + | int |
- | { | + | main(void) |
- | twiWriteData(0x20, 0x05); //write 0x05 @0x20 | + | { |
- | } | + | uint8_t * buf; |
- | return 1; | + | setup(); |
+ | while (1) | ||
+ | { | ||
+ | twi_read_bytes(0x68, 0x42, 1, buf); | ||
+ | } | ||
} | } | ||
</code> | </code> |