i2c_master: sleep to reduce erronous pulse, and use interrupts to wake up
This commit is contained in:
parent
2bd3c4c0b3
commit
64c97740e1
29
i2c_master.c
29
i2c_master.c
|
@ -99,6 +99,7 @@ enum i2c_master_rc i2c_master_start(void)
|
||||||
|
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout count
|
timeout = TIMEOUT; // start timeout count
|
||||||
|
rim(); // enable interrupts
|
||||||
while ((I2C_CR2 & I2C_CR2_START) || !(I2C_SR1 & I2C_SR1_SB) || !(I2C_SR3 & I2C_SR3_MSL)) { // wait until start condition has been accepted, send, and we are in aster mode
|
while ((I2C_CR2 & I2C_CR2_START) || !(I2C_SR1 & I2C_SR1_SB) || !(I2C_SR3 & I2C_SR3_MSL)) { // wait until start condition has been accepted, send, and we are in aster mode
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -109,6 +110,8 @@ enum i2c_master_rc i2c_master_start(void)
|
||||||
if (I2C_CR2 & I2C_CR2_STOP) {
|
if (I2C_CR2 & I2C_CR2_STOP) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
|
|
||||||
return I2C_MASTER_RC_NONE;
|
return I2C_MASTER_RC_NONE;
|
||||||
|
@ -121,6 +124,7 @@ static enum i2c_master_rc i2c_master_wait_stop(void)
|
||||||
{
|
{
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (I2C_CR2 & I2C_CR2_STOP) { // wait until stop condition is accepted and cleared
|
while (I2C_CR2 & I2C_CR2_STOP) { // wait until stop condition is accepted and cleared
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -128,6 +132,8 @@ static enum i2c_master_rc i2c_master_wait_stop(void)
|
||||||
if (I2C_SR2 & (I2C_SR2_BERR | I2C_SR2_ARLO)) {
|
if (I2C_SR2 & (I2C_SR2_BERR | I2C_SR2_ARLO)) {
|
||||||
return I2C_MASTER_RC_BUS_ERROR;
|
return I2C_MASTER_RC_BUS_ERROR;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
// this time we can't use I2C_CR2_STOP to check for timeout
|
// this time we can't use I2C_CR2_STOP to check for timeout
|
||||||
if (I2C_SR3 & I2C_SR3_MSL) { // ensure we are not in master mode anymore
|
if (I2C_SR3 & I2C_SR3_MSL) { // ensure we are not in master mode anymore
|
||||||
|
@ -177,6 +183,7 @@ enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, b
|
||||||
I2C_DR = (slave << 1) | (write ? 0 : 1); // select slave, with read/write flag
|
I2C_DR = (slave << 1) | (write ? 0 : 1); // select slave, with read/write flag
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
|
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -190,12 +197,15 @@ enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, b
|
||||||
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
} else { // 10-bit address
|
} else { // 10-bit address
|
||||||
// send first part of address
|
// send first part of address
|
||||||
I2C_DR = 11110000 | (((slave >> 8 ) & 0x3) << 1); // send first header (11110xx0, where xx are 2 MSb of slave address)
|
I2C_DR = 11110000 | (((slave >> 8 ) & 0x3) << 1); // send first header (11110xx0, where xx are 2 MSb of slave address)
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (!(I2C_SR1 & I2C_SR1_ADD10)) { // wait until address is transmitted (or error)
|
while (!(I2C_SR1 & I2C_SR1_ADD10)) { // wait until address is transmitted (or error)
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -209,12 +219,15 @@ enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, b
|
||||||
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
// send second part of address
|
// send second part of address
|
||||||
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
|
I2C_SR2 &= ~(I2C_SR2_AF); // clear acknowledgement failure
|
||||||
I2C_DR = (slave & 0xff); // send remaining of address
|
I2C_DR = (slave & 0xff); // send remaining of address
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
|
while (!(I2C_SR1 & I2C_SR1_ADDR)) { // wait until address is transmitted (or error)
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -228,6 +241,8 @@ enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, b
|
||||||
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
// go into receive mode if necessary
|
// go into receive mode if necessary
|
||||||
if (!write) {
|
if (!write) {
|
||||||
|
@ -253,6 +268,8 @@ enum i2c_master_rc i2c_master_select_slave(uint16_t slave, bool address_10bit, b
|
||||||
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
if (I2C_SR2 & I2C_SR2_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable relevant I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,6 +300,7 @@ enum i2c_master_rc i2c_master_read(uint8_t* data, uint16_t data_size)
|
||||||
// read data
|
// read data
|
||||||
I2C_CR2 |= I2C_CR2_ACK; // enable ACK by default
|
I2C_CR2 |= I2C_CR2_ACK; // enable ACK by default
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
|
rim(); // enable interrupts
|
||||||
for (uint16_t i = 0; i < data_size; i++) { // read bytes
|
for (uint16_t i = 0; i < data_size; i++) { // read bytes
|
||||||
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
|
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
// set (N)ACK (EV6_3, EV6_1)
|
// set (N)ACK (EV6_3, EV6_1)
|
||||||
|
@ -291,6 +309,7 @@ enum i2c_master_rc i2c_master_read(uint8_t* data, uint16_t data_size)
|
||||||
I2C_CR2 |= I2C_CR2_STOP; // prepare to send the stop
|
I2C_CR2 |= I2C_CR2_STOP; // prepare to send the stop
|
||||||
}
|
}
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (!(I2C_SR1 & I2C_SR1_RXNE)) { // wait until data is received (or error)
|
while (!(I2C_SR1 & I2C_SR1_RXNE)) { // wait until data is received (or error)
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
return I2C_MASTER_RC_TIMEOUT;
|
return I2C_MASTER_RC_TIMEOUT;
|
||||||
|
@ -298,6 +317,8 @@ enum i2c_master_rc i2c_master_read(uint8_t* data, uint16_t data_size)
|
||||||
if (I2C_SR2 & (I2C_SR2_BERR | I2C_SR2_ARLO)) {
|
if (I2C_SR2 & (I2C_SR2_BERR | I2C_SR2_ARLO)) {
|
||||||
return I2C_MASTER_RC_BUS_ERROR;
|
return I2C_MASTER_RC_BUS_ERROR;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable all I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
data[i] = I2C_DR; // read the received byte
|
data[i] = I2C_DR; // read the received byte
|
||||||
}
|
}
|
||||||
|
@ -325,6 +346,7 @@ enum i2c_master_rc i2c_master_write(const uint8_t* data, uint16_t data_size)
|
||||||
I2C_DR = data[i]; // send byte
|
I2C_DR = data[i]; // send byte
|
||||||
I2C_SR2 = 0; // clear error flags
|
I2C_SR2 = 0; // clear error flags
|
||||||
timeout = TIMEOUT; // start timeout counter
|
timeout = TIMEOUT; // start timeout counter
|
||||||
|
rim(); // enable interrupts
|
||||||
while (!(I2C_SR1 & I2C_SR1_TXE)) { // wait until byte has been transmitted
|
while (!(I2C_SR1 & I2C_SR1_TXE)) { // wait until byte has been transmitted
|
||||||
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
|
IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
if (0 == timeout--) {
|
if (0 == timeout--) {
|
||||||
|
@ -339,6 +361,8 @@ enum i2c_master_rc i2c_master_write(const uint8_t* data, uint16_t data_size)
|
||||||
if (I2C_SR2 & I2C_SR2_AF) { // data has not been acknowledged
|
if (I2C_SR2 & I2C_SR2_AF) { // data has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
|
I2C_ITR = (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN); // enable all I²C interrupts
|
||||||
|
wfi(); // got to sleep to prevent EMI causing glitches
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,3 +510,8 @@ enum i2c_master_rc i2c_master_address_write(uint16_t slave, bool address_10bit,
|
||||||
error:
|
error:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i2c_master_isr(void) __interrupt(IRQ_I2C) // I²C event or error happened
|
||||||
|
{
|
||||||
|
I2C_ITR = 0; // disable all interrupt sources to stop looping in ISR and let current loop check the right status flags
|
||||||
|
}
|
||||||
|
|
|
@ -109,4 +109,8 @@ enum i2c_master_rc i2c_master_address_read(uint16_t slave, bool address_10bit, c
|
||||||
* @note start and stop conditions are included
|
* @note start and stop conditions are included
|
||||||
*/
|
*/
|
||||||
enum i2c_master_rc i2c_master_address_write(uint16_t slave, bool address_10bit, const uint8_t* address, uint16_t address_size, const uint8_t* data, uint16_t data_size);
|
enum i2c_master_rc i2c_master_address_write(uint16_t slave, bool address_10bit, const uint8_t* address, uint16_t address_size, const uint8_t* data, uint16_t data_size);
|
||||||
|
/** interrupt service routine used to wake up
|
||||||
|
* @note not sure why the declaration need to be in main for it to work
|
||||||
|
*/
|
||||||
|
void i2c_master_isr(void) __interrupt(IRQ_I2C);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue