Hello world,
I've a problem with my MSP432P401R that I don't understand. I have configured the eUSCI register for I²C in master mode to send and receive data, all works well, except in receiver mode when i read the UCBCNTx field in UCBxSTATW register, this not return the number of bytes received on I²C bus since the last START or RESTART as it's indicate in the Technical Reference Manual p802, but always the value of UCTBCNRx field in UCBxTBCNT register that i have previously indicate. Whereas in transmitter mode all works perfectly. Can someone help me to understand this problem?
here is my code:
/******************************************************************************/ /* @TITRE : i2c.h */ /* @VERSION : 0 */ /* @CREATION : august 20, 2016 */ /* @MODIFICATION : */ /* @AUTEURS : Enzo IGLESIS */ /* @COPYRIGHT : Copyright (c) 2016 Enzo IGLESIS */ /* @LICENSE : MIT License (MIT) */ /******************************************************************************/ #ifndef I2C_H_ #define I2C_H_ /****************************************************************************** * * /|\ /|\ * MSP432P401 R R * master | | * ----------------- | | * | P1.6/UCB0SDA|<-|----+-> * | | | * | | | * | P1.7/UCB0SCL|<-+------> * | | * *****************************************************************************/ /******************************* LIBRARYS *******************************/ /******************************* MACROS *******************************/ #define I2C_R (!0) /* Read */ #define I2C_W (0) /* Write */ #define I2C_ERR (-1) #define i2c_start() (UCB0CTLW0 |= UCTXSTT) #define i2c_stop() (UCB0CTLW0 |= UCTXSTP) #define i2c_start_stop(); (UCB0CTLW0 |= (UCTXSTT|UCTXSTP)) #define i2c_start_is_sent() (UCB0CTLW0&UCTXSTT) #define i2c_stop_is_sent() (UCB0CTLW0&UCTXSTP) #define i2c_bus_busy() (UCB0STATW&UCBBUSY) /******************************* TYPES *******************************/ /******************************* CONSTANTES *******************************/ /******************************* VARIABLES *******************************/ /******************************* FUNCTIONS *******************************/ void i2c_frequency(int_least32_t scl_frequency); void i2c_setup_device(void); void i2c_bytes_to_process(uint8_t counter); void i2c_slave_address(uint8_t address, uint8_t r_w); int i2c_status(void); int i2c_read_write(uint8_t r_w, uint8_t address, uint8_t * data, uint8_t length); int i2c_write(uint8_t address, uint8_t * data, uint8_t length); int i2c_read(uint8_t address, uint8_t * data, uint8_t length); #endif
/******************************************************************************/ /* @TITRE : i2c.c */ /* @VERSION : 0 */ /* @CREATION : august 20, 2016 */ /* @MODIFICATION : */ /* @AUTEURS : Enzo IGLESIS */ /* @COPYRIGHT : Copyright (c) 2016 Enzo IGLESIS */ /* @LICENSE : MIT License (MIT) */ /******************************************************************************/ /******************************* LIBRARYS *******************************/ #include <msp432p401r.h> #include "i2c.h" /******************************* MACROS *******************************/ /******************************* TYPES *******************************/ /******************************* CONSTANTES *******************************/ /******************************* VARIABLES *******************************/ /* IRQHandler */ static volatile uint8_t * rtx_data; static volatile int8_t status; /******************************* FUNCTIONS *******************************/ void i2c_enable_interrupt(void) { UCB0IE |= UCBCNTIE; /* Byte counter interrupt enable */ UCB0IE |= UCNACKIE; /* Not-acknowledge interrupt enable */ UCB0IE |= UCTXIE0; /* Transmit interrupt enable 0 */ UCB0IE |= UCRXIE0; /* Receive interrupt enable 0 */ NVIC_EnableIRQ(EUSCIB0_IRQn); } void i2c_frequency(int_least32_t scl_frequency) { UCB0CTLW0 |= UCSWRST; /* Software reset enable */ UCB0BRW = SystemCoreClock/scl_frequency; /* prescale */ UCB0CTLW0 &= ~UCSWRST; /* Software reset released for operation */ i2c_enable_interrupt(); } void i2c_setup_device(void) { /* Set UCSWRST */ UCB0CTLW0 = UCSWRST; /* Software reset enable */ /* initialize eUSCI_B register */ UCB0CTLW0 &= ~UCA10; /* Own address is a 7-bit address */ UCB0CTLW0 &= ~UCSLA10; /* Address slave with 7-bit address */ UCB0CTLW0 &= ~UCMM; /* Single master environment. There is no other master in the system. The address compare unit is disabled */ UCB0CTLW0 |= UCMST; /* Master mode */ UCB0CTLW0 |= UCMODE_3; /* I2C mode */ UCB0CTLW0 |= UCSYNC; /* Synchronous mode enable */ UCB0CTLW0 |= UCSSEL_3; /* clock source : SMCLK */ UCB0CTLW0 &= ~UCTXACK; /* (slave mode) Do not acknowledge the slave address */ UCB0CTLW0 |= UCTR; /* Transmitter */ UCB0CTLW0 &= ~UCTXSTP; /* No STOP generated */ UCB0CTLW0 &= ~UCTXSTT; /* Do not generate START condition */ UCB0CTLW0 &= ~UCTXNACK; /* Acknowledge normally */ UCB0CTLW1 = 0x0000; /* Reset UCB0CTLW1 */ UCB0CTLW1 &= ~UCETXINT; /* (slave mode) UCTXIFGx is set after an address match with UCxI2COAx and the direction bit indicating slave transmit */ UCB0CTLW1 &= ~UCCLTO_3; /* Disable clock low timeout counter */ UCB0CTLW1 &= ~UCSTPNACK; /* Send a not acknowledge before the STOP condition as a master receiver */ UCB0CTLW1 &= ~UCSWACK; /* The address acknowledge of the slave is controlled by the eUSCI_B module */ UCB0CTLW1 |= UCASTP_2; /* A STOP condition is generated automatically after the byte counter value reached UCBxTBCNT */ UCB0CTLW1 |= UCGLIT_0; /* Deglitch time = 50 ns */ UCB0ADDMASK |= ADDMASK_M; /* the address mask feature is desactivated */ UCB0I2COA0 &= ~UCGCEN; /* Do not respond to a general call */ UCB0I2COA0 &= ~UCOAEN; /* The slave address defined in I2COA0 is disabled */ UCB0I2COA1 &= ~UCOAEN; /* The slave address defined in I2COA1 is disabled */ UCB0I2COA2 &= ~UCOAEN; /* The slave address defined in I2COA2 is disabled */ UCB0I2COA3 &= ~UCOAEN; /* The slave address defined in I2COA3 is disabled */ /* Configure ports */ P1SEL0 |= BIT6; /* Configure P1.6 as SDA */ P1SEL1 &= ~BIT6; P1SEL0 |= BIT7; /* Configure P1.7 as SCL */ P1SEL1 &= ~BIT7; /* Reset UCSWRST */ UCB0CTLW0 &= ~UCSWRST; /* Software reset released for operation */ /* Enable interrupts */ i2c_enable_interrupt(); } void i2c_bytes_to_process(uint8_t counter) { UCB0CTLW0 |= UCSWRST; /* Software reset enable */ UCB0TBCNT &= ~UCTBCNT_M; /* reset Counter Threshold Register */ UCB0TBCNT |= counter; /* set Counter Threshold Register */ UCB0CTLW0 &= ~UCSWRST; /* Software reset released for operation */ i2c_enable_interrupt(); } void i2c_slave_address(uint8_t address, uint8_t r_w) { UCB0I2CSA &= ~I2CSA_M; /* Reset Slave Address Register */ UCB0I2CSA |= address; /* I2C slave address */ if(r_w) /* read */ { UCB0CTLW0 &= ~UCTR; /* Receiver */ } else /* write */ { UCB0CTLW0 |= UCTR; /* Transmitter */ } } int i2c_status(void) { /* local declaration */ int8_t old_status = status; /* program statement */ status = 0; return old_status; } int i2c_read_write(uint8_t r_w, uint8_t address, uint8_t * data, uint8_t length) { while(i2c_bus_busy()); /* Wait until i2c bus is available */ rtx_data = data; status = 0; i2c_bytes_to_process(length); /* set the number of bytes to send */ i2c_slave_address(address, r_w); /* set the slave address in write or read mode */ i2c_start(); /* send an i2c start signal */ /* IRQHandler */ __sleep(); return i2c_status(); /* return the number of bytes processed or -1 if an error occured */ } int i2c_write(uint8_t address, uint8_t * data, uint8_t length) { return i2c_read_write(I2C_W, address, data, length); } int i2c_read(uint8_t address, uint8_t * data, uint8_t length) { return i2c_read_write(I2C_R, address, data, length); } /******************************* INTERRUPT *******************************/ void EUSCIB0_IRQHandler(void) { if(UCB0IFG&UCTXIFG0) /* transmit */ { UCB0TXBUF = rtx_data[(UCB0STATW&UCBCNT_M)>>UCBCNT_OFS]; // Here it's incremented UCB0IFG &= ~UCTXIFG0; } if(UCB0IFG&UCRXIFG0) /* receive */ { UCB0IFG &= ~UCRXIFG0; rtx_data[(UCB0STATW&UCBCNT_M)>>UCBCNT_OFS] = UCB0RXBUF; // Here it's stuck at the number of byte to process } if(UCB0IFG&UCNACKIFG) /* Not-acknowledge received */ { UCB0IFG &= ~UCNACKIFG; i2c_stop(); /* I2C Stop condition */ status = I2C_ERR; __low_power_mode_off_on_exit() } if(UCB0IFG&UCBCNTIFG) /* Byte counter */ { UCB0IFG &= ~UCBCNTIFG; status = UCB0TBCNT&UCTBCNT_M; __low_power_mode_off_on_exit(); } }