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 [2013/03/12 11:01] ldo [Master] |
robotics:computing:communication_twi_entre_atmega [2013/09/27 15:56] (Version actuelle) ldo [Master] |
||
---|---|---|---|
Ligne 55: | Ligne 55: | ||
<code c> | <code c> | ||
/* | /* | ||
- | * twislave.c | + | * twi_slave.c |
* | * | ||
* Created on: 26 févr. 2010 | * Created on: 26 févr. 2010 | ||
Ligne 61: | 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); | ||
+ | } | ||
+ | |||
+ | int | ||
+ | main(void) | ||
+ | { | ||
+ | setup(); | ||
- | while (1) | + | while (1) |
- | { | + | { |
- | } | + | if (rb[0]==0x41) |
- | return 1; | + | { |
+ | tb[0] = 0x47; | ||
+ | tb[1] = 0x49; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | tb[0] = 0x27; | ||
+ | tb[1] = 0x29; | ||
+ | } | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
Ligne 146: | Ligne 169: | ||
Ce code permet d'envoyer une donnée à un esclave. | Ce code permet d'envoyer une donnée à un esclave. | ||
- | Dans un premier temps, on va définir la vitesse de communication en initialisant TWBR et le prescaler dans twiMasterInitialise(). | + | Dans un premier temps, on va définir la vitesse de communication en initialisant TWBR et le prescaler dans twi_master_setup(). |
<code c> | <code c> | ||
/* | /* | ||
Ligne 155: | 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> |