DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Mon Feb 10, 2020 3:38 am

Your original library looks like it works save the text mode. I'm looking to see if I maintain a local framebuffer and transfer all that at once if it would work.

Would this send the whole buffer?

Code: Select all

void SSD1327_UpdateDisplay(void)
{
	GPIO_Output(tab[0].gpio, tab[0].data_cmd_gpio, 1);				// Make sure Data#Cmd high
	SpiWriteAndRead(tab[0].spi, &SSD1327FB, 0, 8192, false);		// Write local framebuffer
}
If so I can get my Framebuffer code out and have it manipulate the buffer.

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Mon Feb 10, 2020 4:00 am

let me just check calc so screenwth is 128 divid by 2 = 64
So full screen is 128 x 64 = 8192

So yep you nailed it but it probably needs to be &SSD1327FB[0]
I assume is defined like uint8_t SSD1327FB[8192];

The code is technically the same but if you have warning levels turned up it sees your code as a pointer to an array of 8192 bytes and it will complain it's not the same as uint8_t*. So you just point to the zeroth item in the array and its saves the warning.

What you saying is also interesting it means it's command problem not an SPI problem.

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Wed Feb 12, 2020 12:42 am

Progress
P_20200211_193109_vHDR_On_1.jpg
P_20200211_193109_vHDR_On_1.jpg (224.36 KiB) Viewed 353 times
The frame buffer is successfully uploaded to the display. With one caveat sending the whole buffer fails I have not tried anything else but to send it one bit at a time.

I recall something about a buffer limit? I'm thinking 8k might be too much data to push to the bus. Does this seem accurate?

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Wed Feb 12, 2020 2:43 am

On the Pi under linux the buffer default limit is 4096 because it 1 virtual page so send the screen in two halfs.
You can make the calls one after another Its just the single call that can't exceed 4096

Line 92 shows you the default buffer size
https://github.com/raspberrypi/linux/bl ... idev.c#L92
You can see what happens if you exceed it

Code: Select all

if (count > bufsiz)
		return -EMSGSIZE;
Alternatively there is an IOcontrol command you can ask for a bigger buffer but I don't know it off top of my head.

Okay looked it up .. it's done in config.txt not IOControl
/boot/cmdline.txt file and add:
spidev.bufsiz=<NEEDED BUFFER SIZE>

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Thu Feb 13, 2020 2:06 am

LdB wrote:
Wed Feb 12, 2020 2:43 am
On the Pi under linux the buffer default limit is 4096 because it 1 virtual page so send the screen in two halfs.
You can make the calls one after another Its just the single call that can't exceed 4096

Line 92 shows you the default buffer size
https://github.com/raspberrypi/linux/bl ... idev.c#L92
You can see what happens if you exceed it

Code: Select all

if (count > bufsiz)
		return -EMSGSIZE;
Alternatively there is an IOcontrol command you can ask for a bigger buffer but I don't know it off top of my head.

Okay looked it up .. it's done in config.txt not IOControl
/boot/cmdline.txt file and add:
spidev.bufsiz=<NEEDED BUFFER SIZE>
Very good to know and now I have done some research on bufsiz. I have modified the code to read /sys/module/spidev/parameters/bufsiz and use that value to determine how much of the buffer to send in one write.

I looked through the data sheet for a quick way to clear the screen but didn't find one.

With this GPIO library is there a way to have a callback function fire if a GPIO changes state, say rising edge and have the GPIO have a pulldown set?

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Thu Feb 13, 2020 3:00 am

The GPIO could but the screen can't do anything like that it's a normal SPI screen and that is one of their weaknesses.
The SPI is just a shift register process and only the Master (the Pi) can initiate anything on the bus lines the screen itself doesn't signal anything. So to do anything smart you can only go on time and use timers with interrupts.

The things you can do is run the SPI at the maximum the screen will support (The datasheet they provide says that is 10Mhz).
You can help by using the "SpiWriteBlockRepeat" function I provide to help with the screen fill.
For example make a small buffer of 64 bytes of a single line filled with the screen colour and then use the "SpiWriteBlockRepeat" with a repeat of 128 times in your case. The more advanced way is to use DMA.

Generally I just put the SPI primitive code in it's own thread with a binary semaphore access lock. So the calling thread(s) and the SPI thread just wait for each other.

For any serious LCD screen projects you are better of getting the HDMI with touchscreen. I buy 5inch 800x480 with touch for around $35USD.

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Thu Feb 13, 2020 2:58 pm

LdB wrote:
Thu Feb 13, 2020 3:00 am
The GPIO could but the screen can't do anything like that it's a normal SPI screen and that is one of their weaknesses.
The SPI is just a shift register process and only the Master (the Pi) can initiate anything on the bus lines the screen itself doesn't signal anything. So to do anything smart you can only go on time and use timers with interrupts.

The things you can do is run the SPI at the maximum the screen will support (The datasheet they provide says that is 10Mhz).
You can help by using the "SpiWriteBlockRepeat" function I provide to help with the screen fill.
For example make a small buffer of 64 bytes of a single line filled with the screen colour and then use the "SpiWriteBlockRepeat" with a repeat of 128 times in your case. The more advanced way is to use DMA.

Generally I just put the SPI primitive code in it's own thread with a binary semaphore access lock. So the calling thread(s) and the SPI thread just wait for each other.

For any serious LCD screen projects you are better of getting the HDMI with touchscreen. I buy 5inch 800x480 with touch for around $35USD.
The end goal of my OLED is a status display for a server with a simple button and possibly a rotary encoder interface.

I was hoping to use callback functions when a button was pressed or I turn an encoder. I try to avoid polling if callbacks are available.

The HDMI screen sounds interesting if it can be shut down and powered up by the pi ...

I was looking into the gpio.c and I see CheckEvent ClearEvent and EdgeDetect is there a way to use these to fire callbacks, even if that's shifted off to it's own thread to use a polling setup? With other interfaces like input events or CEC I don't have to poll I can have a thread wait for an event and then call the callback function for that event.

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Fri Feb 14, 2020 1:10 pm

You can setup all the normal interrupts and callbacks you are talking to a standard driver.

Now my device OLED arrived today and it took but a few minutes to work out the errors on the datasheet.
It is an SPI_MODE_3 device it works in SPI_MODE_0 but gets touchy about long wires in mode 0 because the clock edges are right on the fringe. I can run it at 10Mhz with 1 metre cable.

There is a document and sample code error with command 0x15
The X co-ordinates is in bytes not pixels (so you have to divid x by 2)
The Y co-ordinate is in pixels
The reason is obvious because on X there are two pixels one in high nibble, one in low.
If they ran the set window in pixels they would have the complexity in the auto increment action

The datasheet says nothing about this and in fact you can only set even addresses because of the div 2
10.1.1Set Column Address (15h) This triple byte command specifies column start address and end address of the display data RAM. This command also sets the column address pointer to column start address. This pointer is used to define the current read/write column address in graphic display data RAM. If horizontal address increment mode is enabled by command A0h, after finishing read/write one column data, it is incremented automatically to the next column address. Whenever the column address pointer finishes accessing the end column address, it is reset back to start column address and the row address is incremented to the next row.

I extended to sample to have two tasks one to display the time ticking and another increment a count. You then have to use a semaphore so the access to the screen is orderly because one task may be firing data down the SPI bus when the other wants to access it and so it must wait for the other task to complete.

Anyhow all working
https://github.com/LdB-ECM/SSD1327_Linux
Image

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Fri Feb 14, 2020 4:20 pm

LdB wrote: Now my device OLED arrived today and it took but a few minutes to work out the errors on the datasheet.
It is an SPI_MODE_3 device it works in SPI_MODE_0 but gets touchy about long wires in mode 0 because the clock edges are right on the fringe. I can run it at 10Mhz with 1 metre cable.

There is a document and sample code error with command 0x15
The X co-ordinates is in bytes not pixels (so you have to divid x by 2)
The Y co-ordinate is in pixels
The reason is obvious because on X there are two pixels one in high nibble, one in low.
If they ran the set window in pixels they would have the complexity in the auto increment action

The datasheet says nothing about this and in fact you can only set even addresses because of the div 2
10.1.1Set Column Address (15h) This triple byte command specifies column start address and end address of the display data RAM. This command also sets the column address pointer to column start address. This pointer is used to define the current read/write column address in graphic display data RAM. If horizontal address increment mode is enabled by command A0h, after finishing read/write one column data, it is incremented automatically to the next column address. Whenever the column address pointer finishes accessing the end column address, it is reset back to start column address and the row address is incremented to the next row.

I extended to sample to have two tasks one to display the time ticking and another increment a count. You then have to use a semaphore so the access to the screen is orderly because one task may be firing data down the SPI bus when the other wants to access it and so it must wait for the other task to complete.

Anyhow all working
https://github.com/LdB-ECM/SSD1327_Linux
Image
I'm getting different output I did a fresh compile.
P_20200214_105407_vHDR_On_1.jpg
P_20200214_105407_vHDR_On_1.jpg (152.3 KiB) Viewed 186 times
I'm impressed with the performance boost. I'm not worried about the output of the sample I thought it would be helpful for you to see it run on another device. The pattern background is slow to draw, afterwards it's very smooth.

It's was great having your help with this I now have a useable display and now I have something that works as I thought it should.
LdB wrote: You can setup all the normal interrupts and callbacks you are talking to a standard driver.
Forgive me for asking I read the datasheet, my thoughts are I should use a thread to poll for the interrupt and fire a callback from there? I don't see a way to simplify this to

Code: Select all

 attached_callback (GPIO, type, callback)
My understanding is that I set the GPIO to input, and set the pull-up or pull-down ,attached the interrupt to rising or falling, the. In a polling loop check for the event if I find on clear it and fire the callback.

Your GPIO code does not seem to have pulling resistors set up in it, is that an advanced feature that requires the base address?

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Fri Feb 14, 2020 4:54 pm

Sorry I am losing it ... I added font size change to code and managed to not copy the source file to Git

This line in SSD1327.c

Code: Select all

if ((((i + 1) % 4) == 0) && ((i + 1) < tab[0].fontwth))
Was supposed to be this reflecting we write two bits at a time

Code: Select all

if ((((i + 1) % 4) == 0) && ((i + 1) < tab[0].fontwth/2))

Can you try a recompile now, So I can put this all to bed and you have working source :-)

I also threw up a sample 3 different size fonts and how you need to tackle that
https://github.com/LdB-ECM/SSD1327_Linux_v1

/dev/gpiomem does give you access to the Fixed resistors I just have never had need of them so never did the code.

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Fri Feb 14, 2020 7:59 pm

LdB wrote: Sorry I am losing it ... I added font size change to code and managed to not copy the source file to Git

This line in SSD1327.c

Code: Select all

if ((((i + 1) % 4) == 0) && ((i + 1) < tab[0].fontwth))
Was supposed to be this reflecting we write two bits at a time

Code: Select all

if ((((i + 1) % 4) == 0) && ((i + 1) < tab[0].fontwth/2))

Can you try a recompile now, So I can put this all to bed and you have working source :-)

I also threw up a sample 3 different size fonts and how you need to tackle that
https://github.com/LdB-ECM/SSD1327_Linux_v1

/dev/gpiomem does give you access to the Fixed resistors I just have never had need of them so never did the code.
That's better here's the output
P_20200214_144656_vHDR_On_1.jpg
P_20200214_144656_vHDR_On_1.jpg (162.56 KiB) Viewed 150 times
Looks good.

I haven't checked out your other code yet, I will later on though. I'm using PSF Fonts in my Framebuffer project.
P_20200214_145228_vHDR_On_1.jpg
P_20200214_145228_vHDR_On_1.jpg (111.56 KiB) Viewed 150 times
These display is not easy to photograph I have to play with all kinds of setting to get something that looks alright.

It looks easy enough to add pull up or down calls when I get a moment I'll try it out then I will share the code here could be useful for others.

LdB
Posts: 1429
Joined: Wed Dec 07, 2016 2:29 pm

Re: Libraries for SPI and GPIO in 2020

Fri Feb 14, 2020 10:15 pm

It isn't so much the font that it was explaining it is the function of the thing called a device context. I got the impression you had not written much multithreaded code and if I have that wrong ignore all the next discussion.

As we have threads writing to the screen each one may have a different font and text colours. So the device context holds all that data and the write functions now require a handle to a device context. So each thread if it wants to use the screen gets it's own device context which it will use for the text calls.

In that way as you draw say text from one thread it has one set of colours and font and another thread will have a different set of colours and fonts the switch is automatic. The primitives nor the caller needs to be concerned about saving those settings because the primitives use the data on the context from the caller. Usually you would also take the semaphore into the device context structure so it isn't just floating around but I have not done that yet. I wasn't sure if you knew all this stuff or not and how far to go.

If you haven't seen it before the process of semaphore lock and a device context is generic it is how you easily setup multiple access of threads to a single device if it isn't already provided by the driver. It may give you hints for working with other things like the GPIO because often you may want one thread accessing certain GPIOs and another thread accessing other GPIO's but those GPIO share the same registers (in many cases 32 GPIO share 1 register). If you run the two threads in that situation crazy things happen because the two threads foul up the single register.

So for example thread1 reads a GPIO register and masks off the current value then gets switched out and another thread runs and it reads and the writes a new register value. Now thread1 resumes and promptly writes back the old register value killing everything the second thread did. So using GPIO access from multiple threads will generally require the minimum of a semaphore and often a device context to carry data that is thread specific.

Everything said about threads equally applies if you have interrupts accessing the GPIO or SPI and you have access to those same devices outside the interrupt. Anyhow enough said we have covered the basics.

DarkElvenAngel
Posts: 292
Joined: Tue Mar 20, 2018 9:53 pm

Re: Libraries for SPI and GPIO in 2020

Sat Feb 15, 2020 1:09 am

LdB wrote:
Fri Feb 14, 2020 10:15 pm
It isn't so much the font that it was explaining it is the function of the thing called a device context. I got the impression you had not written much multithreaded code and if I have that wrong ignore all the next discussion.

As we have threads writing to the screen each one may have a different font and text colours. So the device context holds all that data and the write functions now require a handle to a device context. So each thread if it wants to use the screen gets it's own device context which it will use for the text calls.

In that way as you draw say text from one thread it has one set of colours and font and another thread will have a different set of colours and fonts the switch is automatic. The primitives nor the caller needs to be concerned about saving those settings because the primitives use the data on the context from the caller. Usually you would also take the semaphore into the device context structure so it isn't just floating around but I have not done that yet. I wasn't sure if you knew all this stuff or not and how far to go.

If you haven't seen it before the process of semaphore lock and a device context is generic it is how you easily setup multiple access of threads to a single device if it isn't already provided by the driver. It may give you hints for working with other things like the GPIO because often you may want one thread accessing certain GPIOs and another thread accessing other GPIO's but those GPIO share the same registers (in many cases 32 GPIO share 1 register). If you run the two threads in that situation crazy things happen because the two threads foul up the single register.

So for example thread1 reads a GPIO register and masks off the current value then gets switched out and another thread runs and it reads and the writes a new register value. Now thread1 resumes and promptly writes back the old register value killing everything the second thread did. So using GPIO access from multiple threads will generally require the minimum of a semaphore and often a device context to carry data that is thread specific.

Everything said about threads equally applies if you have interrupts accessing the GPIO or SPI and you have access to those same devices outside the interrupt. Anyhow enough said we have covered the basics.
I appreciate that break down, I have written a few multiple thread programs but haven't used semaphore locks. I tend to use a method of thread control, buffers, and have only have the main thread do the main tasks. The most complex multiple thread application I wrote was for a touchscreen control with serial and network connections. I had no cross talking between threads only the main thread reading/writing thread states and thread data is read or write only.

I've never done anything that requires semaphores I haven't come across a race condition in my code.

That said reading the source code I understand how they work better than the theory I had read previously.

Return to “C/C++”