Need help making this library work for my RPI. I'm having issues drawing a simple "Hello World" string but nothing is being shown on the display. Am I missing an implementation in the code below?
Pin Config
| ST7920 | SPI | Wiring Pi Pin # | BCM Pin # |
|-------- |------ |----------------- |----------- |
| RS | CS | 10 | 8 |
| R/W | MOSI | 12 | 10 |
| EN | CLK | 14 | 11 |
| RST | | 22 | 6 |
| PSB | | GND | |
Test Code:
int main()
{
u8g2_t u8g2;
u8g2_Setup_st7920_128x64_f(&u8g2, U8G2_R0, u8g2_rpi_spi_byte_cb, u8g2_rpi_gpio_and_delay_cb);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_ncenB14_tr);
u8g2_DrawStr(&u8g2, 0, 15, "Hello World");
u8g2_SendBuffer(&u8g2);
return 0;
}
HAL - SPI
uint8_t u8g2_rpi_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
switch(msg) {
case U8X8_MSG_BYTE_INIT: {
if (wiringPiSetup() == -1) {
printf("WiringPi Error\n");
exit(1);
}
if (wiringPiSPISetup(0, 100000) < 0) {
printf("Unable to open SPI device 0: %s\n", strerror(errno));
exit(1);
}
printf("Initialized SPI Hardware\n");
break;
}
case U8X8_MSG_BYTE_SET_DC: {
break;
}
case U8X8_MSG_BYTE_START_TRANSFER: {
break;
}
case U8X8_MSG_BYTE_END_TRANSFER: {
break;
}
case U8X8_MSG_BYTE_SEND: {
wiringPiSPIDataRW(0, arg_ptr, arg_int);
break;
}
default: {
return 0;
}
}
return 1;
}
HAL - GPIO:
uint8_t u8g2_rpi_gpio_and_delay_cb(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
//printf("U8X8_MSG_GPIO_AND_DELAY_INIT: %d\n", arg_int);
if (u8g2_rpi_hal.dc != U8G2_RPI_HAL_UNDEFINED) {
//printf("Set OUTPUT mode to pin DC/RS\n");
pinMode(u8g2_rpi_hal.dc, OUTPUT);
}
if (u8g2_rpi_hal.reset != U8G2_RPI_HAL_UNDEFINED) {
//printf("Set OUTPUT mode to pin RESET\n");
pinMode(u8g2_rpi_hal.reset, OUTPUT);
}
break; // can be used to setup pins
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
delayMicroseconds(10);
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
delay(arg_int);
break;
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
if (u8g2_rpi_hal.reset != U8G2_RPI_HAL_UNDEFINED) {
digitalWrite(u8g2_rpi_hal.reset, arg_int);
}
break;
return 1;
}
Both procedures are incomplete.
For the byte procedure, have a look here: https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_byte.c#L88
For SPI with the 7920 indeed the dc line is not required, but you need to handle the chip select signal (u8x8_gpio_SetCS). The chip select message also needs to be handled in the GPIO and delay procedures.
no further comment, closing...
Apologies for not being able to get back at you regarding this issue.
Good news, I FINALLY managed to make everything work (both hardware and software SPI implementations) and I would like to share my findings here.
TLDR; For the complete solution/demo, I have uploaded the cpp project here
Couple of issues I have encountered:
The SPI HW communication of the raspberry pi was not working (Confirmed through test between RPI and Arduino slave)
After reviewing the gpio status via the gpio tool, I realized that the MOSI, CLOCK and CS pins were set to OUT instead of ALT0.
Solution:
By explicitly setting the pin modes to ALT0 during initialization, I was able to establish proper SPI HW communication. The wiring pi spi library does not set this during initialization so you have to do it yourself.
pinModeAlt(u8g2_rpi_hal.mosi, 0b100);
pinModeAlt(u8g2_rpi_hal.clk, 0b100);
pinModeAlt(u8g2_rpi_hal.cs, 0b100);
Even after fixing the SPI HW issue and copying the example from the port guide , replaced the arduino SPI methods with it's Wiring Pi equivalent, I was still unable to make it work (no response/activity from the display).
I then stumbled into a comment of your code found in 'u8x8_byte_arduino_hw_spi':
U8x8lib.cpp: u8x8_byte_arduino_hw_spi
// 1.6.5 offers a block transfer, but the problem is, that the
// buffer is overwritten with the incoming data
// so it can not be used...
// SPI.transfer((uint8_t *)arg_ptr, arg_int);
This comment led me to investigate the inner workings of the Wiring Pi SPI library. From the developer's website, I found that the 'wiringPiSPIDataRW' also overwrites the data in the buffer in the same manner of what the comment above described and It uses ioctl system calls for full-duplex SPI transfer operations.
*int wiringPiSPIDataRW (int channel, unsigned char *data, int len) :
>
This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus.
I also found out from the linux kernel docs that Chip Select is automatically set/unset for full-duplex operations.
Standard read() and write() operations are obviously only half-duplex, and
the chipselect is deactivated between those operations. Full-duplex access,
and composite operation without chipselect de-activation, is available using
the SPI_IOC_MESSAGE(N) request.
Unfortunately, the Wiring Pi SPI library does not provide any other methods of transfer and is only limited to full-duplex transfer operations, so I ended up writing my own spi library which supports block transfers for half-duplex operations with the intention to have u8g2 regain control of the Chip Select pin.
With this, after replacing the wiring pi methods I was able to make everything work.
Wow, thanks a lot for your detailed feedback.
Also thanks for the updates to https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform
Most helpful comment
Apologies for not being able to get back at you regarding this issue.
Good news, I FINALLY managed to make everything work (both hardware and software SPI implementations) and I would like to share my findings here.
TLDR; For the complete solution/demo, I have uploaded the cpp project here
Couple of issues I have encountered:
The SPI HW communication of the raspberry pi was not working (Confirmed through test between RPI and Arduino slave)
After reviewing the gpio status via the gpio tool, I realized that the MOSI, CLOCK and CS pins were set to OUT instead of ALT0.
Solution:
By explicitly setting the pin modes to ALT0 during initialization, I was able to establish proper SPI HW communication. The wiring pi spi library does not set this during initialization so you have to do it yourself.
Even after fixing the SPI HW issue and copying the example from the port guide , replaced the arduino SPI methods with it's Wiring Pi equivalent, I was still unable to make it work (no response/activity from the display).
I then stumbled into a comment of your code found in 'u8x8_byte_arduino_hw_spi':
U8x8lib.cpp: u8x8_byte_arduino_hw_spi
This comment led me to investigate the inner workings of the Wiring Pi SPI library. From the developer's website, I found that the 'wiringPiSPIDataRW' also overwrites the data in the buffer in the same manner of what the comment above described and It uses ioctl system calls for full-duplex SPI transfer operations.
*int wiringPiSPIDataRW (int channel, unsigned char *data, int len) :
>
I also found out from the linux kernel docs that Chip Select is automatically set/unset for full-duplex operations.
Unfortunately, the Wiring Pi SPI library does not provide any other methods of transfer and is only limited to full-duplex transfer operations, so I ended up writing my own spi library which supports block transfers for half-duplex operations with the intention to have u8g2 regain control of the Chip Select pin.
With this, after replacing the wiring pi methods I was able to make everything work.