Closed Pacimani closed 4 years ago
You probably need to implement hardware SPI: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform#atmel-avr
My own example is a pure software solution which drives the data / clock lines manually via port commands: https://github.com/olikraus/u8g2/blob/master/sys/avr/as7/main.c#L112
Instead you would need an implementation which will use the SPI subsystem of your controller. Something like this: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform#hardware-spi-communication but specific to your target controller.
Thanks for your prompt response Oli. I see the example, this is pretty involving. I am new to Atmel studio, and honestly, I don't know how and where to start. I implement an IMU in my project such that the LCD rotates from 0 to 360 degree based on the acceleration due to gravity on the device; to achieve this, I am using the u8g2_SetDisplayRotation and u8g3_DrawFame(to go into different mode on LCD with different contents on screen). I believe this is the reason why the update mode is pretty slow. Any help would be appreciated.
Not sure how I can help here
See the third link in my first reply as starting point to improve speed.
Thank you for your help Oli. Between these two function, which one can I implement (or change) uint8_t u8x8_avr_gpio_and_delay(u8x8_t u8x8, uint8_t msg, uint8_t arg_int, void arg_ptr) uint8_t u8x8_avr_delay(u8x8_t u8x8, uint8_t msg, uint8_t arg_int, void arg_ptr)
This is the README, This directory contains code that can be shared across all AVR uC, when developing with https://www.nongnu.org/avr-libc/.
Please refer to https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform to understand what is here.
At lib/u8x8_avr.h, you can find:
u8x8_byte_avr_hw_spi
Implements HW SPI communication. To use it, you're required to define SCK and MOSI ports externally (see example Makefiles).
u8x8_avr_delay
Implements the delay functions that are required by the GPIO and Delay callback function.
This means, you have to write little code to support your own project.
Please refer to the existing main.c and Makefile examples for details on how to use it.
I visited the link in the README but there is no place where I can see this _lib/u8x8_avr.h_
Hi Oli, I am sorry to bother you again.I found the library and edited it to suit my board How can I use now? Thanks.
Looks like, i missed your comment 5 days back.
I found the library and edited it to suit my board How can I use now? Thanks.
Not sure what you mean by "library", but if you have the neccessary byte and deley functions, then you can just use this sequence:
u8g2_t u8g2; // a structure which will contain all the data for one display
...
u8g2_Setup_ssd1306_i2c_128x64_noname_2(&u8g2, U8G2_R0, my_byte_fn, my_delay_fn); // 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
Of course you have to choose your own setup procedure for your display. They are all listed here: https://github.com/olikraus/u8g2/wiki/u8g2setupc
Also note that there are details on seting up the display here: https://github.com/olikraus/u8g2/wiki/u8g2setupc#introduction
Thank you very much. Made it!
:-)
@Pacimani hey how did you go about doing this, im currently struggling with the same concept, did you just alter the u8x8_byte_avr_hw_spi and u8x8_avr_delay functions?
@olikraus Hi, im trying to do the same thing as @Pacimani did, but im trying to translate the arduino code for the hardwire spi communication from https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform#atmel-avr and i have no idea how to translate this to avr. Any help would be great. Ive currently set up the GPIO and Delay callback for my specific LCD st7920
Hi, It pretty easy to do it. If you are using atmega328p which was in my case, the pins are already defined. Just comment out the pin definition in .c file and you can get rid of I2C codes as well since you don't need it. Then you can follow the example in main
@Pacimani sorry which .c file and which main file? we are using atmega328P as well If you could could you show us in person? we are also apart of engg
@Pacimani, im more so confused on how to tranlsate this to avr for the atmega
xtern "C" uint8_t u8x8_byte_arduino_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
uint8_t *data;
uint8_t internal_spi_mode;
switch(msg) {
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;
while( arg_int > 0 ) {
SPI.transfer((uint8_t)*data);
data++;
arg_int--;
}
break;
case U8X8_MSG_BYTE_INIT:
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
SPI.begin();
break;
case U8X8_MSG_BYTE_SET_DC:
u8x8_gpio_SetDC(u8x8, arg_int);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
/* SPI mode has to be mapped to the mode of the current controller, at least Uno, Due, 101 have different SPI_MODEx values */
internal_spi_mode = 0;
switch(u8x8->display_info->spi_mode) {
case 0: internal_spi_mode = SPI_MODE0; break;
case 1: internal_spi_mode = SPI_MODE1; break;
case 2: internal_spi_mode = SPI_MODE2; break;
case 3: internal_spi_mode = SPI_MODE3; break;
}
SPI.beginTransaction(SPISettings(u8x8->display_info->sck_clock_hz, MSBFIRST, internal_spi_mode));
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
break;
case U8X8_MSG_BYTE_END_TRANSFER:
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
SPI.endTransaction();
break;
default:
return 0;
}
return 1;
}
@Pacimani , ive got this for my avr_delay and gpio_delay
uint8_t u8x8_avr_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t cycles;
switch(msg)
{
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
// At 20Mhz, each cycle is 50ns, the call itself is slower.
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
// Approximate best case values...
#define CALL_CYCLES 26UL
#define CALC_CYCLES 4UL
#define RETURN_CYCLES 4UL
#define CYCLES_PER_LOOP 4UL
cycles = (100UL * arg_int) / (P_CPU_NS * CYCLES_PER_LOOP);
if(cycles > CALL_CYCLES + RETURN_CYCLES + CALC_CYCLES)
break;
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (cycles) : "0" (cycles) // 2 cycles
);
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
for(int i=0 ; i < arg_int ; i++)
_delay_us(10);
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
for(int i=0 ; i < arg_int ; i++)
_delay_ms(1);
break;
default:
return 0;
}
return 1;
}
uint8_t u8x8_avr_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
// Re-use library for delays
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
DISPLAY_CLK_DIR |= 1<<DISPLAY_CLK_PIN;
DISPLAY_DATA_DIR |= 1<<DISPLAY_DATA_PIN;
DISPLAY_CS_DIR |= 1<<DISPLAY_CS_PIN;
DISPLAY_RESET_DIR |= 1<<DISPLAY_RESET_PIN;
break; // can be used to setup pins
case U8X8_MSG_GPIO_SPI_CLOCK: // Clock pin: Output level in arg_int
if(arg_int)
DISPLAY_CLK_PORT |= (1<<DISPLAY_CLK_PIN);
else
DISPLAY_CLK_PORT &= ~(1<<DISPLAY_CLK_PIN);
break;
case U8X8_MSG_GPIO_SPI_DATA: // MOSI pin: Output level in arg_int
if(arg_int)
DISPLAY_DATA_PORT |= (1<<DISPLAY_DATA_PIN);
else
DISPLAY_DATA_PORT &= ~(1<<DISPLAY_DATA_PIN);
break;
case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
if(arg_int)
DISPLAY_CS_PORT |= (1<<DISPLAY_CS_PIN);
else
DISPLAY_CS_PORT &= ~(1<<DISPLAY_CS_PIN);
break;
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
if(arg_int)
DISPLAY_RESET_PORT |= (1<<DISPLAY_RESET_PIN);
else
DISPLAY_RESET_PORT &= ~(1<<DISPLAY_RESET_PIN);
break;
default:
if (u8x8_avr_delay(u8x8, msg, arg_int, arg_ptr)) // check for any delay msgs
return 1;
u8x8_SetGPIOResult(u8x8, 1); // default return value
break;
}
return 1;
}
This is the place where you can find the codes for hardware spi, you don't need to convert Arduino to avr. https://github.com/olikraus/u8g2/tree/master/sys/avr/avr-libc/lib
Here is the example in the main. You can get rid of the codes you currently have and use these three functions.(the one in the main as your delay and the two function is the library above). also get rid of I2C codes. https://github.com/olikraus/u8g2/blob/master/sys/avr/avr-libc/atmega328p/main.c
Hi Oli, I am using u8g2 on a small project(with atnmega328p) in Atmel studio, and the LCD is updating very slow. Is there a way that I can increase the update speed? Thanks