Assigning I2C pins manually
Page last updated
05 Sep 2014, by
Hung Bui.
4
replies
In some hardware setups you may want to change the I2C pins (SDA & SCL) manually, different from the default one (P22-sda and P20-scl). To do that you would need to access the hardware configuration registers directly.
For I2C on the nRF51822, it's the NRF_TWI0->PSELSCL and the NRF_TWI0->PSELSDA you need to modify.
Here is an example that I re-configure the pin to P1-SCL and P2-SDA:
void I2C_reconfigure_pins (void)
{
NRF_GPIO->PIN_CNF[p2] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
NRF_GPIO->PIN_CNF[p1] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
NRF_TWI0->PSELSCL = p1;//scl;
NRF_TWI0->PSELSDA = p2;//sda;
}
Since in the I2C library from mbed, the I2C pins got reset and reconfigured back to default one every time there is a unsuccessful transmission, we need to call I2C_reconfigure_pins() before every I2C API call.
Attached here is an example of a modified version of the MMA7660FC so that pin P1, and P2 is assigned for I2C pins: /media/uploads/nemovn/mma7660.cpp
Note: you still have to initiate MMA7660 MMA(p22, p20); with the default pin P22 and P20 otherwise you will receive the error from mbed since the pin wasn't correctly.
4 comments on Assigning I2C pins manually :
The need to call this before every I2C call makes it pretty awkward. I just modify the library sources when I need to change the I2C pins (though, of course, that is awkward for other reasons).
The need to call this before every I2C call makes it pretty awkward. I just modify the library sources when I need to change the I2C pins (though, of course, that is awkward for other reasons).
Exactly, I hope mbed provides a native support for this soon. For example, it would be great if we could change the pin assignments by #define expressions directly within the main file.
Hmm there probably is not very pretty way without modifying the mbed common API. Here's a somewhat "cleaner" approach to it:
http://developer.mbed.org/users/jaerts/code/I2CX/
Just replace I2C with I2CX in your library and specify the peripheral in the constructor.
example
// Read from I2C slave at address 0x62
#include "mbed.h"
#include "I2CX.h"
I2CX i2c(I2C_0, p28, p27);
int main() {
int address = 0x62;
char data[2];
i2c.read(address, data, 2);
}
One possible solution is to make the peripheral argument optional in the mbed API.
Very nice...
How to do the same with SPI?
Hmm there probably is not very pretty way without modifying the mbed common API. Here's a somewhat "cleaner" approach to it:
http://developer.mbed.org/users/jaerts/code/I2CX/
Just replace I2C with I2CX in your library and specify the peripheral in the constructor.
example
// Read from I2C slave at address 0x62
#include "mbed.h"
#include "I2CX.h"
I2CX i2c(I2C_0, p28, p27);
int main() {
int address = 0x62;
char data[2];
i2c.read(address, data, 2);
}
One possible solution is to make the peripheral argument optional in the mbed API.
Please log in to post comments.
The need to call this before every I2C call makes it pretty awkward. I just modify the library sources when I need to change the I2C pins (though, of course, that is awkward for other reasons).