New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

U8g2 with Texas Instruments C2000 Launchpad (F28027F / F28069M...) #549

Closed
blotfi opened this Issue Mar 25, 2018 · 20 comments

Comments

Projects
None yet
2 participants
@blotfi

blotfi commented Mar 25, 2018

Hi
Is there a port of this excellent library to the TI TMS320 C2000 DSC using I2C or SPI
I am aware of
https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform
Thanks

@olikraus

This comment has been minimized.

Owner

olikraus commented Mar 25, 2018

I am not aware about such a port. Did you check the porting guide in the project wiki?

@blotfi

This comment has been minimized.

blotfi commented Mar 26, 2018

Yes, no one did it :-(

@olikraus

This comment has been minimized.

Owner

olikraus commented Mar 26, 2018

Then.... I would say, it is not that difficult. You could just start with the gpio and delay procedure until you have a working prototype.

@blotfi blotfi closed this Mar 28, 2018

@blotfi blotfi reopened this Apr 28, 2018

@blotfi

This comment has been minimized.

blotfi commented Apr 28, 2018

Hi again
I managed to get the SSD1306 OLED run with hardware I2C on C2000 plateform (F28069M and F28027F Piccolo Teaxas Instruments).
Here is the code
https://github.com/blotfi/c2000_OLED_SSD1306

Can you help me to port U8G2 to this plateform?
Thanks

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 28, 2018

So, your OLED works, but you want to use u8g2 with I2C, right?

All information should be here: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform

For hardware I2C; the gpio and delay procedure can be very small, because no GPIO is required, but only the delay part:

uint8_t u8x8_gpio_and_delay_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  switch(msg)
  {
    case U8X8_MSG_GPIO_AND_DELAY_INIT:	// called once during init phase of u8g2/u8x8
      break;							// can be used to setup pins
    case U8X8_MSG_DELAY_NANO:			// delay arg_int * 1 nano second
      DSP28x_usDelay(arg_int/1000);
      break;    
    case U8X8_MSG_DELAY_100NANO:		// delay arg_int * 100 nano seconds
      DSP28x_usDelay(arg_int/10);
      break;
    case U8X8_MSG_DELAY_10MICRO:		// delay arg_int * 10 micro seconds
      DSP28x_usDelay(arg_int*10);
      break;
    case U8X8_MSG_DELAY_MILLI:			// delay arg_int * 1 milli second
      while( arg_int-- > 0 )
         DSP28x_usDelay(1000);
      break;
    case U8X8_MSG_DELAY_I2C:				// arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
      break;							// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
}

ok, if I took over your delay procedure, thats it for your gpio & delay procedure.

U8X8_MSG_DELAY_I2C can be ignored, it is only required for software emulated I2C. In fact if I remember correctly, only the milliseconds delay is required for HW I2C.

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 28, 2018

The second procedure is a new CAD procedure. This is a deviation from the porting guide, but it has been discussed here in the issues. Maybe I need to update the porting guide. You could also create a byte transfer procedure, but after review of your existing procedures, I think it is better to write a CAD procefure. So, here is my suggestion for your project:

uint8_t u8x8_cad_ssd13xx_i2c_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  uint8_t *p;
  switch(msg)
  {
    case U8X8_MSG_CAD_SEND_CMD:
    case U8X8_MSG_CAD_SEND_ARG:
      oledCommand( arg_int );		// I2C address of the OLED is hardcoded in this procedure
      break;
    case U8X8_MSG_CAD_SEND_DATA:
      {
	// In order to reuse i2c_Xfer, all the data is copied to a new array
	// Probably there is a better solution, but then i2c_Xfer needs to be replaced
	// by a different procedure
	
	// prepare a new array with data
	uint8_t data[258];
	uint16_t i = 0;
	data[i] = 0x040;
        for( i = 0; j < arg_int; j++ )
	  data[i+1] = arg_ptr[i];
	
	// transfer the data in the new array
	i2c_Xfer( u8x8_GetI2CAddress(u8x8), bytes, 2, NULL, 0 );
      }
      break;
    case U8X8_MSG_CAD_INIT:
      /* apply default i2c adr if required so that the start transfer msg can use this */
      if ( u8x8->i2c_address == 255 )
	u8x8->i2c_address = 0x078;
      return u8x8->byte_cb(u8x8, msg, arg_int, arg_ptr);
    case U8X8_MSG_CAD_START_TRANSFER:
    case U8X8_MSG_CAD_END_TRANSFER:
      /* ignored */
      break;
    default:
      return 0;
  }
  return 1;
}
@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 28, 2018

Finally you have to setup the u8g2 object:

u8g2_t u8g2; // a structure which will contain all the data for one display
...
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_c2000);  // init u8g2 structure
u8g2.u8x8.cad_cb = u8x8_cad_ssd13xx_i2c_c2000; // use our own CAD procedure
u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
u8g2_SetPowerSave(&u8g2, 0); // wake up display

If there is sufficient RAM, you could also use the "f" variant of the setup procedure: u8g2_Setup_ssd1306_i2c_128x64_noname_f.

... of course nothing is tested here...

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 28, 2018

Ok, I have another solution, which avoids rewriting the cad procedure.
Instead the byte procedure is rewritten. I think this solution is much better and
more clean.

The complete source code follows. You just need to integrate this into your code.

uint8_t u8x8_gpio_and_delay_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  switch(msg)
  {
    case U8X8_MSG_GPIO_AND_DELAY_INIT:	// called once during init phase of u8g2/u8x8
      break;							// can be used to setup pins
    case U8X8_MSG_DELAY_NANO:			// delay arg_int * 1 nano second
      DSP28x_usDelay(arg_int/1000);
      break;    
    case U8X8_MSG_DELAY_100NANO:		// delay arg_int * 100 nano seconds
      DSP28x_usDelay(arg_int/10);
      break;
    case U8X8_MSG_DELAY_10MICRO:		// delay arg_int * 10 micro seconds
      DSP28x_usDelay(arg_int*10);
      break;
    case U8X8_MSG_DELAY_MILLI:			// delay arg_int * 1 milli second
      while( arg_int-- > 0 )
         DSP28x_usDelay(1000);
      break;
    case U8X8_MSG_DELAY_I2C:				// arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
      break;							// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
}

uint8_t u8x8_byte_i2c_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  static uint8_t buffer[32];		/* u8g2/u8x8 will never send more than 32 bytes */
  static uint8_t buf_idx;
  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:
      /* init i2c communication */
      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:
      i2c_Xfer( u8x8_GetI2CAddress(u8x8), buffer, buf_idx, NULL, 0 );
      break;
    default:
      return 0;
  }
  return 1;
}


u8g2_t u8g2; // a structure which will contain all the data for one display
...
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_i2c_c2000, u8x8_gpio_and_delay_c2000);  // init u8g2 structure
u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
u8g2_SetPowerSave(&u8g2, 0); // wake up display

@blotfi

This comment has been minimized.

blotfi commented Apr 28, 2018

thanks but I am running into lot of errors
What do I have to do to use 8x8 lib
I copied the csrc directrory to my C2000 project directory
I add in https://github.com/blotfi/c2000_OLED_SSD1306/blob/master/oled.c
the 2 routines you mentionned
add
u8g2_t u8g2;
and make the calls of
u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_i2c_c2000, u8x8_gpio_and_delay_c2000); // init u8g2 structure
u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
u8g2_SetPowerSave(&u8g2, 0); // wake up display
in my InitI2C(), after configuring I2C

add in oled.h
#include <u8x8.h>

uint8_t u8x8_gpio_and_delay_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_byte_i2c_c2000(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
extern u8g2_t u8g2;

also I have to modify u8x8.h
by adding,
typedef unsigned char uint8_t;

So far it is not compiling

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 28, 2018

Can I see the code on your github repo? Please also post the errors.

uint8_t is defined in <stdint.h>

@blotfi

This comment has been minimized.

blotfi commented Apr 28, 2018

https://github.com/blotfi/c2000_u8g2/

ok, now I can compile
but not enough memory ! (look to oled27f.map)
I will change from the F28027F to F28069M (which is another kind of beast)
and try

@blotfi

This comment has been minimized.

blotfi commented Apr 28, 2018

void i2c_Xfer(
Uint8 address,
Uint8* wdata, int wsize,
Uint8* rdata, int rsize )
but you indicate buffer position as wsize ?

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 29, 2018

but not enough memory ! (look to oled27f.map)

U8g2 depends a lot on link time optimization. This means, that unused functions and unused data objects are removed. This did not happen during linking with your environment.
For gcc this is available (so called linker garbage collector) and this is also default for Arduino Environment. For other systems you need to consult the linker manual. Sometimes these options are only available with the professional version of the compiler/linker.

but you indicate buffer position as wsize ?

which means?

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 29, 2018

ah, ok, you need make a forward declaration of
void i2c_Xfer(
Uint8 address,
Uint8* wdata, int wsize,
Uint8* rdata, int rsize )

I mean the byte function calls i2c_Xfer before it is defined. so either place a prototype if i2c_Xfer before the byte function or define the byte function after i2c_Xfer.

@blotfi

This comment has been minimized.

blotfi commented Apr 29, 2018

no I am not speaking about the forward declaration, of course I did it (it will not compile if so)
I am speaking about the difference between my function i2c_Xfer https://github.com/blotfi/c2000_u8g2/blob/master/oled.c
and the way you use it
wsize is the number of bytes in the wdata buffer to transfer
but now that I red your function I don't understood why the 2 function are not in the same case

`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_END_TRANSFER:
  i2c_Xfer( u8x8_GetI2CAddress(u8x8), buffer, buf_idx, NULL, 0 );
  break;`

I mean, you can fill the buffer then you transmit it directly...

@blotfi

This comment has been minimized.

blotfi commented Apr 29, 2018

@blotfi

This comment has been minimized.

blotfi commented Apr 30, 2018

I went on another device with much more memory F28069M instead of F28027F just to see if the u8g2 can be used for C2000 devices
I still have this optimisation issue, for example : u8g2_d_memory.c
will ask to allocate lot of memory in the .ebss section
RAML0_L8 : origin = 0x008000, length = 0x00B800
as I am Flashing to RAM, lot of things goes to this RAM, but it is big : 46 k

.text : > RAML0_L8, PAGE = 0
.cinit : > RAMM0, PAGE = 0
.pinit : > RAMM0, PAGE = 0
.switch : > RAMM0, PAGE = 0
.reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */

.stack : > RAMM1, PAGE = 1
.ebss : > RAML0_L8, PAGE = 0
.econst : > RAML0_L8, PAGE = 0
.esysmem : > RAML0_L8, PAGE = 0

@olikraus

This comment has been minimized.

Owner

olikraus commented Apr 30, 2018

u8g2_d_memory.c will ask to allocate lot of memory in the .ebss section

Again: U8g2 requires a link garbage collector. It is a standard feature in the Arduino gcc toolchain. You can run U8g2 with lesser than 1K of RAM.

What about the "-mo" option as adviced in the TI forum? Will it work?

@blotfi

This comment has been minimized.

blotfi commented Apr 30, 2018

of course I put it
run the compiler with a max level of optimisation regarding code size...
the pb is that it does reserve memory it will never use (no link garbage collector)
I don't know how to fix this

@olikraus

This comment has been minimized.

Owner

olikraus commented May 11, 2018

ok, I can not support here... feel free to reopen...

@olikraus olikraus closed this May 11, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment