Assigning I2C pins manually

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 :

15 Oct 2014

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).

19 Oct 2014

Jan Szymanski wrote:

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.

22 Oct 2014

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.

04 Nov 2014

Very nice... How to do the same with SPI?

Joris Aerts wrote:

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.