This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSPM0G3507: I2C Porting for u8g2 Library

Part Number: MSPM0G3507


Hi, 

is there any porting example for u8g2 library for MSPM0G series MCU using i2c HW connection? 

I just would like to know how the HAL for I2C byte send callback looks like as its HW i2c can support only 8 FIFOs. How to split and implement into this callback function?

Just FYI, below is the sample provided for Arduino I2C.

uint8_t u8x8_byte_arduino_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  switch(msg)
  {
    case U8X8_MSG_BYTE_SEND:
      Wire.write((uint8_t *)arg_ptr, (int)arg_int);
      break;
    case U8X8_MSG_BYTE_INIT:
      Wire.begin();
      break;
    case U8X8_MSG_BYTE_SET_DC:
      break;
    case U8X8_MSG_BYTE_START_TRANSFER:
      if ( u8x8->display_info->i2c_bus_clock_100kHz >= 4 )
      {
	Wire.setClock(400000L); 
      }
      Wire.beginTransmission(u8x8_GetI2CAddress(u8x8)>>1);
      break;
    case U8X8_MSG_BYTE_END_TRANSFER:
      Wire.endTransmission();
      break;
    default:
      return 0;
  }
  return 1;
}

  • Hi, 

    is there any porting example for u8g2 library for MSPM0G series MCU using i2c HW connection? 

    No.

    How to split and implement into this callback function?

    You can refer to the SDK example: i2c_controller_rw_multibyte_fifo_poll

    Line 66 ~ Line 98 is the I2C sending function.

    SDK file path: C:\ti\mspm0_sdk_2_00_00_03\examples\nortos\LP_MSPM0G3507\driverlib\i2c_controller_rw_multibyte_fifo_poll

    Or online information: https://dev.ti.com/tirex/explore/node?node=A__APMYG0JHpn6P7h6dhMw7DQ__MSPM0-SDK__a3PaaoK__LATEST

    its HW i2c can support only 8 FIFOs.

    For FIFO usage, you can refer to the same SDK demo. Another you need to confirm is Tx FIFO trigger level configured in syscfg, here:

    And for the data length longer than 8 bytes, you can call this API to waiting for TX FIFO empty and fill it with new data:

    DL_I2C_isControllerTXFIFOEmpty(I2C_INST);

    Regards,

    Helic

  • Hi Helic,

    thanks so much for the reply, 

    Just a few more clarifications, if I use

    DL_I2C_isControllerTXFIFOEmpty(I2C_INST);

    I cannot use this:

        /* Send the packet to the controller.
         * This function will send Start + Stop automatically.
         */
        DL_I2C_startControllerTransfer(I2C_INST, Addr,
            DL_I2C_CONTROLLER_DIRECTION_TX, 2);

    as this will send Start+Stop automatically, right?
    So do I need to use other API?

    Thanks and Regards,

    Anthony.

  • Hi, 

    I cannot use this:

    You can set your actually size in the param if DL_I2C_startControllerTransfer, can be larger than 8.

    After transfer start, waiting for TxFIFO is empty by jam CPU using this flag read:

    DL_I2C_isControllerTXFIFOEmpty(I2C_INST);

    Or you can refer to this threads, since both of you need transfer >8 length of data.

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1352378/mspm0g3507-i2c-master-controller-multiple-data-more-the-8-bytes-transfer-polling-example

    Regards,

    Helic

  • Hi Helic,

    thanks for the reply again. So basically, 

    I should just use 

    "DL_I2C_startControllerTransfer" with (let's say) 16bytes of length and wait for TXFIFO to be empty and refill with 8more bytes but I don't need to recall this startControllerTransfer function again as this will be automatically transfer the next batch of FIFO data. Is that so? 

  • Hi, Anthony

    Is that so? 

    Yes!

    You can have a look at i2c controller rw multibyte fifo interrupt, this is a >8 bytes sending example.

    Regards,

    Helic

  • Hi Helic,

    thanks so much for the reply. I used your code snippet to test it out and I found one issue.

                /*
                * Fill FIFO with data.
                */
                g_u8TxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[0], buf_idx);
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
                /* Send the packet to the controller.
                * This function will send Start + Stop automatically.
                */
                DL_I2C_startControllerTransfer(I2C_INST, OLED_I2C_ADDR,
                    DL_I2C_CONTROLLER_DIRECTION_TX, buf_idx);
    
                /* Poll until the Controller writes all bytes */
                while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
    
                while (g_u8TxCount < buf_idx) {
                    interrupt = DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
                    //Waiting for txfifo empty
                    while (interrupt != DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY )
                    {
                        ;
                    }
                    //clear interrupt
                    DL_I2C_clearInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
     
                    DL_I2C_flushControllerTXFIFO(I2C0);               
    
                    //Write more data to I2C FIFO
                    g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
    
                 /* Poll until the Controller writes all bytes */
                 while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
                }        
    
    
    
                /* Trap if there was an error */
                if (DL_I2C_getControllerStatus(I2C_INST) &
                    DL_I2C_CONTROLLER_STATUS_ERROR) {
                    /* LED will remain high if there is an error */
                    __BKPT(0);
                }
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE))
                ;
    
                DL_I2C_flushControllerTXFIFO(I2C0);

    I am able to poll until the controller writes all bytes and the code passed this stage for the first time.

                /*
                * Fill FIFO with data.
                */
                g_u8TxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[0], buf_idx);
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
                /* Send the packet to the controller.
                * This function will send Start + Stop automatically.
                */
                DL_I2C_startControllerTransfer(I2C_INST, OLED_I2C_ADDR,
                    DL_I2C_CONTROLLER_DIRECTION_TX, buf_idx);
    
                /* Poll until the Controller writes all bytes */
                while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);

    But the second time, it's polling forever meaning I2C couldn't finish writing all other bytes.

                while (g_u8TxCount < buf_idx) {
                    interrupt = DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
                    //Waiting for txfifo empty
                    while (interrupt != DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY )
                    {
                        ;
                    }
                    //clear interrupt
                    DL_I2C_clearInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
     
                    DL_I2C_flushControllerTXFIFO(I2C0);               
    
                    //Write more data to I2C FIFO
                    g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
    
                /* Poll until the Controller writes all bytes */
                while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
                }  

    Could you please help me to look at this issue?

    Is there any more API that i need to call before I poll for this stage?

    Thanks and Regards,

    Anthony Thet.

  • Hi, 

    You need jam CPU here and check Status every while loop.

    It's not workable if you do in this way↓: There are still some logical issue.

    interrupt = DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
    //Waiting for txfifo empty
    while (interrupt != DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY )
    {
        ;
    }

    Try to follow this code:

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1352378/mspm0g3507-i2c-master-controller-multiple-data-more-the-8-bytes-transfer-polling-example

    But the second time, it's polling forever meaning I2C couldn't finish writing all other bytes.

    Yes, because in while you won't update the interrupt value.

    Regards,

    Helic

  • Hi Helic,

    thanks. Now I tried with the code you have mentioned and able to drive OLED but the images are corrupted and sometime flickering. so when I debugged , I found this issue.

                /*
                * Fill FIFO with data.
                */
                g_u8TxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[0], buf_idx);
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
                /* Send the packet to the controller.
                * This function will send Start + Stop automatically.
                */
                DL_I2C_startControllerTransfer(I2C_INST, OLED_I2C_ADDR,
                    DL_I2C_CONTROLLER_DIRECTION_TX, buf_idx);
    
                while( g_u8TxCount < buf_idx) 
                {   /* Wait Till TXFIFO Empty*/
                    // while(!DL_I2C_isControllerTXFIFOEmpty(I2C_INST))
                    // ;
                    Waiting for txfifo empty
                    while (!(DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY)))
                    ;
                    //clear interrupt
                    DL_I2C_clearInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
                    g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
                }

    In the first "DL_I2C_fillControllerTXFIFO" function, "g_u8TxCount" received return value 8.

                /*
                * Fill FIFO with data.
                */
                g_u8TxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[0], buf_idx);

    But in the second "DL_I2C_fillControllerTXFIFO" function 

                while( g_u8TxCount < buf_idx) 
                {   /* Wait Till TXFIFO Empty*/
                    // while(!DL_I2C_isControllerTXFIFOEmpty(I2C_INST))
                    // ;
                    Waiting for txfifo empty
                    while (!(DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY)))
                    ;
                    //clear interrupt
                    DL_I2C_clearInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
                    g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
                }

    instead of getting 16, g_u8TxCount received 17 meaning fillControllerTXFIFO writes 9bytes of data. I think that's why the display images are corrupted. How should I able to address this?

  • Hi, 

    Try to observe this 9 bytes on hardware. Make sure hardware signal is correct.

    g_u8TxCount received 17 meaning fillControllerTXFIFO writes 9bytes of data.

    Regards,

    Helic

  • Hi Helic,

    I have tried with the same EVK with porting arduino library (which needs just two bytes to write) and it works perfectly well.
    I don't know why and I just tried this just to able to make sure only 8bytes are written everytime and the OLED Display still flickers.

                while( g_u8TxCount < buf_idx) 
                {   /* Wait Till TXFIFO Empty*/
                    // while(!DL_I2C_isControllerTXFIFOEmpty(I2C_INST))
                    // ;
                    //Waiting for txfifo empty
                    while (!(DL_I2C_getRawInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY)))
                    ;
                    //clear interrupt
                    DL_I2C_clearInterruptStatus(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY);
                    
                    if(buf_idx - g_u8TxCount > 8)
                    {
                        g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], 8);
                    }
                    else {
                        g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
                    }
                    // g_u8TxCount += DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[g_u8TxCount], buf_idx - g_u8TxCount);
                }

    Is there any example for Master Controller transmit I2C with DMA transfer? I would like to try this because the current polling method seems too slow.

    Thanks and Regards,

    Anthony Thet.

  • Hi, 

    Here is the demo code of I2C controller Tx,Rx with DMA:

    4527.i2c_controller_rw_dma_fifo_interrupts_LP_MSPM0G3507_nortos_ticlang.zip

    Regards,

    Helic

  • Hi Helic, 

    noted and thanks so much for your help and assist throughout the whole time.

  • Hi Helic,

    I'm just able to drive SSD1316 OLED display through I2c using u8g2 library after some changes in my application code.

    Just would like to share my HAL driver code for MSPM0G3507.

    uint8_t u8x8_gpio_and_delay_mspm0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
    {
    	  switch (msg)
    	  {
    	  case U8X8_MSG_GPIO_AND_DELAY_INIT:
            delay_cycles(32000);//1ms
    	    break;
    	  case U8X8_MSG_DELAY_MILLI:
            for(uint8_t i=0; i < arg_int; i++)
            {
                delay_cycles(32000);
            }
    
    	    break;
    	  case U8X8_MSG_GPIO_DC:
    	    break;
    	  case U8X8_MSG_GPIO_RESET:
            if (arg_int)
            {
                  DL_GPIO_setPins(GPIO_OLED_PORT, GPIO_OLED_RST_OLED_PIN);
    		}
            else
            {
                DL_GPIO_clearPins(GPIO_OLED_PORT, GPIO_OLED_RST_OLED_PIN);
    		}
    	    break;
    	  }
    	  return 1;
    }
    
    
    uint8_t u8x8_byte_mspm0_hw_i2c (u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, void *arg_ptr)
    {
      /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
      /* add extra byte for the i2c address */
      static uint8_t buffer[34];
      static volatile uint8_t buf_idx, g_u8TxCount;
      uint8_t *data;  
      switch(msg)
      {
        case U8X8_MSG_BYTE_SEND:
            data = (uint8_t *)arg_ptr;
            while( arg_int > 0 )
            {
                buffer[buf_idx++] = *data;
                data++;
                arg_int--;
            }
                break;
    
        case U8X8_MSG_BYTE_INIT:
                /* add your custom code to init i2c subsystem */
    
                break;
        case U8X8_MSG_BYTE_SET_DC:
                /* ignored for i2c */
                break;
        case U8X8_MSG_BYTE_START_TRANSFER:
                buf_idx = 0;       
                break;
        case U8X8_MSG_BYTE_END_TRANSFER:
                /*
                * Fill FIFO with data.
                */
                g_u8TxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &buffer[0], buf_idx);
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
                /* Send the packet to the controller.
                * This function will send Start + Stop automatically.
                */
                DL_I2C_startControllerTransfer(I2C_INST, OLED_I2C_ADDR,
                    DL_I2C_CONTROLLER_DIRECTION_TX, buf_idx);
    
                while(g_u8TxCount < buf_idx)
                {
                    while(DL_I2C_isControllerTXFIFOFull(I2C_INST)==true)
                    ;
                    DL_I2C_transmitControllerData(I2C_INST, buffer[g_u8TxCount]);
                    g_u8TxCount++;
                }
    
                /* Poll until the Controller writes all bytes */
                while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
    
                /* Trap if there was an error */
                if (DL_I2C_getControllerStatus(I2C_INST) &
                    DL_I2C_CONTROLLER_STATUS_ERROR) {
                        while(1);
                }
    
                /* Wait for I2C to be Idle */
                while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
                DL_I2C_flushControllerTXFIFO(I2C_INST);
    
                break;
    
        default:
                return 0;    
      }
      return 1;
    }