This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

i2c/twi detup on register level

Hello I'm trying to setup i2c/twi communication between nrf52832 with oled driver SH1107 but i need to do it in hardware instead of software but on the register level.

void initI2c()
{
	NRF_TWIM0->SHORTS = 0x00001780;
	NRF_TWIM0->INTEN = 0x019C0022;
	NRF_TWIM0->ERRORSRC = 0x00000006;
	NRF_TWIM0->PSEL.SCL	= 0x0000000D;
	NRF_TWIM0->PSEL.SDA = 0x0000000E;
	NRF_TWIM0->FREQUENCY = 0x06400000;
	NRF_TWIM0->ADDRESS = 0x0000078;
	NRF_TWIM0->ENABLE = 0x00000006;
}

void WriteTwiCommand (unsigned char Data)
{
	#define BUFFER_SIZE 2
	typedef struct ArrayList
	{
		uint8_t buffer[BUFFER_SIZE];
	} ArrayList_type;
	ArrayList_type MyArrayList[2];
	NRF_TWIM0->TXD.MAXCNT = BUFFER_SIZE;
	NRF_TWIM0->TXD.PTR = &MyArrayList;  // here it says (incompativle pointer to integer conversion when i copied that from the datasheet) 
	NRF_TWIM0->TASKS_STARTTX;
}

this is my code guys for the twi initialization and for sending transmission to slave. i need my nrf52 to act as a master only so i chose TWIM for that reason. im very new to communication protocols so please be patient with me. also if something in my question is not clear or missing, please let me know so i can clear it up as best i can.

  • This line,

    NRF_TWIM0->SHORTS = 0x00001780;
    

    enables all shorts. Enable only one of them, like LASTTX_STOP. Which sets the stop signal after last byte has been transferred.

    Here you enable interrupt on all events:

    NRF_TWIM0->INTEN = 0x019C0022;
    

    Enable only the ones you need. In your example above, you don't use interrupts at all, so you should set this register to 0.

    This line,

    NRF_TWIM0->ERRORSRC = 0x00000006;
    

    is only used for checking the error source when an error is encountered. Do not write to this register.

    You must write 1 to TASKS_STARTTX like this:

    NRF_TWIM0->TASKS_STARTTX = 1;
    

    MyArrayList must be static so that the pointer is valid after the function returns. Something like this should work:

    #define BUFFER_SIZE 2
    #define TWI_SCL 13
    #define TWI_SDA 14
    typedef struct ArrayList
    {
        uint8_t buffer[BUFFER_SIZE];
    } ArrayList_type;
    
    static ArrayList_type tx_buf[2];
    static ArrayList_type * tx_buf_p = tx_buf;
    
    void initI2c()
    {
        NRF_GPIO->PIN_CNF[TWI_SCL] = (6 << 8) | (3 << 2); //configure pins with pullup
        NRF_GPIO->PIN_CNF[TWI_SDA] = (6 << 8) | (3 << 2);
        NRF_TWIM0->SHORTS = (1 << 9);     //LASTTX_STOP
        NRF_TWIM0->PSEL.SCL = TWI_SCL;
        NRF_TWIM0->PSEL.SDA = TWI_SDA;
        NRF_TWIM0->FREQUENCY = 0x06400000;  //400kbps
        NRF_TWIM0->ADDRESS = 0x0000078;
        NRF_TWIM0->ENABLE = 6;
    }
    
    void WriteTwiCommand (uint8_t * Data)
    {
        // copy data to TX buffer:
        for(int i = 0; i < BUFFER_SIZE; i++){
            tx_buf[0].buffer[i] = Data[i];
        }
        NRF_TWIM0->TXD.MAXCNT = BUFFER_SIZE;
        NRF_TWIM0->TXD.LIST = 1;
        NRF_TWIM0->TXD.PTR = (uint32_t)tx_buf_p; //typecast pointer to uint32_t to get rid of warning.
        NRF_TWIM0->TASKS_STARTTX = 1;
    }
    int main(void)
    {
        initI2c();
        uint8_t data[BUFFER_SIZE] = {1,2}; // data you want to transmit
        WriteTwiCommand(data);
        while (true)
        {
            __WFE(); // CPU to sleep
        }
    }
    

    Anyways, why do you want to write directly to the registers like this? You should use the hardware driver in the SDK, it will save you a lot of trouble.

Related