Wednesday, June 7, 2023

I now understand why I couldn't access or control the HPS_LTC_GPIO signal on LTC pin 14 - vendor buffoonery

FOUND A SIMILAR COMPLAINT SEARCHING THE WEB

I came across another hobbyist who had the same experience as me - other HPS GPIO signals could be read using the GPIO memory mapped interface, reflecting whether the external pin associated with that signal had 3.3V or 0 applied to it. However, they too were unable to read any value or set it to output a 1 state. This was for a slightly different board, the DE0-Nano but it was a clue. 

In the helpful response, somebody mentioned that the schematic shows a DNI (do not install) for the resistor that connects the HPS chip pad for HPS_LTC_GPIO with pin 14 on the LTC connector. In other words, pin 14 isn't wired to anything. I opened the schematic for the DE10-Nano board to see how that pin is wired on my board

LOOKED AT ACTUAL SCHEMATIC FOR THE LTC CONNECTOR OF DE10-NANO

Darn - same DNI notation illustrating that we have no connection at all to the HPS chip pads. 

COMPARING THIS TO THE MISLEADING USER MANUAL FOR THE BOARD

If instead you read all the user documentation this GPIO signal on LTC is listed as an available resource. Here is the schematic and table from that manual which misleadingly show that signal connected to pin 14. 

You can see that the table clearly implies that the pin 14 signal is connected to Cyclone V chip pad H13, yet the schematic and my tests prove otherwise. The diagram above the table shows a direct wire between pad H13 and LTC pin 14, wherease the schematic shows a resistor position in that line with an infinite (missing) resistor. 

VENDOR BUFFOONERY STRIKES AGAIN

The Terasic boards such as the DE10-Nano were the official reference boards for the Altera Cyclone V system on a chip, with the golden reference design based on those boards. Intel bought Altera's business and continued to publish the golden reference designs, documents and everything else, but obviously nobody has actually looked closely enough to see that this could NEVER work and has not worked on several versions of the development boards. 

That accounts for a few hours of my time wasted entirely, some of it attempting access to a pin that is not connected to anything and some of it spent with documentation poring over the many thousands of pages. 

BMP arrow code completed and SPI not being controlled by Linux driver

CHECKED THE DEVICE TREE BLOB FOR LINUX - SPIM0 IS NOT CONTROLLED

Linux makes use of a device tree to control the devices and define addressing/control information for all the device/function drivers. This is stored in a compressed 'blob' format, file suffix dtb, but the compiler which creates the blob can reverse it to give me the source file (dts suffix). Looking over the tree that was produced with my instance of Linux for the HPS side, I see that SPIm0 is disabled, thus I should be able to control it freely. 

BMP ARROW CODE CLEAN AND EASY

I was surprised as I dug into the commands and parameters I would be sending to the LCD controller to find out that it had a pair of commands, 0x2A and 0x2B, which set the left/right limits and the top/bottom limits for streaming pixel data. 

That is, if I set the left and right limits to the sides of the arrow position on the screen and set the top and bottom correspondingly, then when I stream in 130 lines consisting of 130 pixels, they will set only the pixels in that bound area. 

I had been expecting to have to reset the current position at the start and then after each line, writing just 130 pixels between each alteration, but this windowed mode is exactly what I need. 

HPS_LTC_GPIO TEST STILL FAILS

I attempted to set as an output GPIO40, which I generated to connect to the HPS_LTC_GPIO signal from the connector. It failed to emit a 1 value, just as it has failed to report input values. Just when I thought I fully understood, after months, the obscure signal routing for HPS signals, once again it doesn't do what I expected. 

Building BMP images for the user interface

UP AND DOWN ARROWS

I found a green up arrow image at http://cliparts.co/circular-arrow-clip-art and edited it to the desired 130x130 pixel size. I also rotated it 180 degrees and saved it as a down arrow image. 


I have a placeholder for the 2315 disk cartridge image that I want to display while the drive is active. This one is from a site that does not allow use for commercial purposes. I will take my own picture of a cartridge and process it to the 480x320 size I need, replacing this placeholder. I actually created it the wrong way, narrow and tall, sigh 

CHANGING CODE TO LOAD THESE SMALLER BMP FILES ON MY USER INTERFACE

I had to create a modified version of the LCD_BMP.c code that was provided with the Waveshare library with the LCD Module purchase, as that file will only load a BMP that is exactly screen size. I need a version that will load the 130x130 sized arrow images and will place it in the desired location on the screen. 

Testing this will need to wait until I have the LCD Module up and working, but it was a coding task I could take on while I was waiting for my cables and jumpers to arrive.

Reshuffle of pin assignments and very minor hitch

NO LONGER NEED THE EXTRA FEATURES OF THE FPGA LINK TO THE SPI HARDWARE

I originally brought the SPI hardware out to the FPGA side because that offered me four slave select lines as well as an input to block the SPI clock in case more than one SPI master was sharing the line. Gradually those features were not needed or didn't work as I expected.

The input block signal never seemed to work, so I moved over to a different way of detecting that the -pick signal had gone back to high state. I had planned to leverage two of the slave select lines to provide the LCD Reset and LCD Command/Data signal to the LCD Module, but realized they didn't activate when I set them, only while bytes were being transmitted by the SPI link. I found other means to control those signals as well. 

At this point I only need the major SPI signals clock, MOSI and MISO, not even slave select since I am ignoring that output and using a different means of sending slave select to the LCD and touch controller chips. There is no longer an advantage and in fact since I had to instantiate buffer elements in the FPGA to drive the GPIO pins from these signals, I was introducing some delays that might be impacting the SPI behavior. 

LTC CONNECTOR DESIGNED TO PROVIDE SPI OR I2C CONNECTION

The Linear Technologies Corporation (LTC) connector was a means of connecting some peripherals to embedded systems, with many of those peripherals using I2C or SPI serial signaling over the connector. Terasic provided an LTC connector on the DE10-Nano board and this seemed the more natural and reliable way to connect my SPI lines. 

The connector is a two row by seven pin (2x7) but using 2mm spacing and smaller .5mm square pins that the usual 2.54mm style such as the GPIO 1 and GPIO 2 connectors on the board. Of the 14 pins, LTC customs mean that we have 3.3V, 9V and ground supplied taking up at least 4 of the 14. In addition, this board connects three more to ground, thus we have only seven pins available for signals.

The seven pins provide the clock, MOSI, MISO and slave select for SPI plus a clock and data line for I2C. However, they also implemented a pin called HPS_LTC_GPIO for general purpose input output in case a module connected to the LTC needed a discrete control line in addition to serial communications. 

The astute reader realizes that these come to a total of 8 signals over only 7 pins. This introduces a wrinkle, in that two of the pins are actually connected through a solid state DPDT relay, controlled by the state of the GPIO pin. 

If GPIO is low, pins 4 and 7 are connected to the SPI clock and MOSI inside the chip. If GPIO is high, pins 4 and 7 are connected to I2C clock and data. The I2C clock and data are also connected to pins 11 and 9 directly. This means that you can always connect the I2C but depending on the use of the GPIO pin, you might not be able to use the SPI. 

SMALL COMPLICATION

The connector uses smaller pins which means my current jumper wires won't connect reliably. The connector ends of the jumpers are also too wide to fit side by side if I need to hook them to adjacent pins. This blocked me from checking the SPI behavior with the scope until I resolve this.

I have a proper connector and cable for the LTC specs coming as well as jumpers that fit on 2mm pins then the other side fits on the more usual 2.54mm pin. Once I have these I can wire up the module and also observe with the scope. My testing has to wait a couple of days until I have all of this in hand. 

ONE WORRY

I had observed a few odd behaviors about the LTC connections and SPI in prior tests. This raises the possibility that some driver in Linux is already controlling SPI and the GPIO pin; I would need to disable this driver in order to have unimpeded access to both. 

I had tried to use the FPGA connection to SPI as a way of injecting the -pick signal to the master contention signal so that it would block clock output but also be detectable by reading the status registers of the SPI. I was never able to see that signal in the status register no matter what I did.

At another point I had hoped to use the HPS_LTC_GPIO pin as a input to detect the interrupt request from the touch controller on the LCD Module. Although I attempted to control it both as input and output, I was not successful. 

Now, this may have been due to a misunderstanding I had earlier about how to connect to the HPS side connectors. They are attached to the HPS side of the chip and one would presumable have access without needing the FPGA logic to be involved. However, that is not the case. 

Even when using HPS features purely from the HPS, one has to set the peripheral pin settings in the Platform Designer, connect the resulting signals inside the FPGA logic to the HPS signal pin, in order for this to work. If I have idle time I may do a test with HPS_LTC_GPIO now that I understand the nonintuitive connectivity process. It is not an urgent matter so no definite plan to check this. 

Monday, June 5, 2023

Drawing on the LCD screen to test functions I need - part 3

PAPER VERIFICATION OF CIRCUIT UNDER DIFFERENT SPI MODES

The four modes vary based on two factors - the idle level of the clock signal (CPOL) and the phase of the clock at which the incoming bits are latched (CPHA). The rising edge of a clock is when it transitions from its idle level to the opposite logic state, and the phase means whether the latching is rising or falling edge of the clock. 

When I look at the datasheet for the XPT2046 controller chip for the touch screen, it clearly shows the clock idle at 0 level and the the signals latched at the rising edge of that clock. This should be mode 0, with CPOL 0 and CPHA 0. 


The diagram for the LCD module has some 7400 series ICs cobbled together to drive a 16 bit parallel LCD controller chip, such that it would work connected to an SPI master.

The chip on the right is an inverter, although the labeling of the pins is not consistent with the chip. Pin 1 on the top left is the input and pin 2 is the inverted output for a 7404 hex inverter chip type. 

The chip on the left is a counter which is reset whenever chip select is high - that is whenever slave select is not asserted - then it counts on the rising edge of the clock input. Bit Q3 is the output - this goes high when the counter gets up to 8 and then stays high until we wrap around to 16 when it drops again.

The middle two chips are 8 bit Serial In Parallel Output shift registers that will accept the state of pin 2, MOSI, at each rising edge of the clock SCLK. Thus it is shifting in the incoming values at every CPHA 0 of polarity CPOL 0. The strobe pin 1 transfers the state of the shift register bits to output latches when it is high then the latch holds its value all the time that strobe is low.

The effect of the counter as the strobe input is that shifting of input data is invisible on the parallel output pins until transferred by having strobe high. As we count up from the start of a string of incoming clock and input pulses, pushing them into the shift register, we get the current value visible in the output latches once the strobe goes high, with those values changing with each additional input clock cycle until strobe goes back low. At that time we have frozen the value of the 8 bits even if additional MOSI bits are coming in. 

The serial output of the final bit of one chip is fed into the second chip as its data (in place of MOSI). This the two together form a 16 bit SIPO shift register, with the latched outputs appearing right after eight bits were shifted in and continuing to update until we have reached 16 bits. This supports the odd behavior of this module where we can send 8 bit, 16 bit or n*16 bit messages. 

At the end of 8 bits shifted into the first register, the strobe coming from the counter chip makes the contents available on the parallel outputs. If the chip select (slave select) is turned off then the counter is reset, the clock stops cycling and LCD module takes a look at the incoming parallel data. 

From the 8th to the 16th bit shifting in, parallel outputs show the current shifted value of the register, but at the 16th count it is frozen by the strobe going low again. When chip select is turned off after 16 bits, the LCD module looks at the 16 parallel values and processes it accordingly.

If we have shifted in 16 bits but don't turn off chip select, instead continuing to cycle the clock and deliver additional bits on MOSI, then the pair of shift registers hold the value of the first 16 bit word in spite of new data cycling in on clock counts 17 up to 23. At count 24 up to 32 the parallel outputs are changing as the data shifts in but again are frozen when strobe goes low at 32 ( and all subsequent multiples of 16 clock cycles).

The inverter on the right means that the LCD Clock signal is high whenever we have a locked in frozen set of parallel output values, either 8, 16 or any of the multiple 16 bit words. The LCD controller chip sees this LCD Clock as well as the chip select (slave select).

The ILI9488 LCD controller chip supports many interface methods but we have hard wired the mode pins to select the DBI Type B 16 bit interface. This is a parallel 16 bit interface with a chip select, a write strobe, a reset, a data/command and LED turnon signals in addition to the 16 data ones. The controller chip supports reads with various commands that will send back data, but that requires a read strobe pin that is not connected nor is the data out connected to the SPI MISO line. 

This confused me for a while since the code issues a read command to determine whether it is this 3.5" LCD module or a smaller 2.8" that is supported by the same library of code. The code determines it is the 3.5" module because the data returned is x00 but of course that is what you would see if the MISO line were not connected as is the case here. The 2.8" module must implement MISO and the read strobe pins. 

This foils one of my three tests for communications, where I believed I could issue a command that would read some manufacture identification information and send it back over SPI, but without the wiring I will always get zero. I will have to figure out the most minimum set of commands I can send to cause some detectible behavior on the screen. 

All of the above investigation makes me very comfortable that I have correctly identified this as mode 0, that is CPOL 0 and CPHA 0. What is a bit harder to determine is the bit order of transmission. We know that a command is just 8 bits with a (premature) termination via chip select (slave select) deactivation at that time. Thus the command bits were shifted in so that the high bit as defined in the data sheet is the last one shifted in. For a command such as xB0, we would see MOSI sending bits 0, 0, 0 0, 1, 1, 0, 1 on the MOSI wire. 

I write a xB0 into the 8 bit data register of the SPI master, with bit 0 on the right so that bit 7 is 1, continuing down to bit 0 having a 0, just as the contents will be in the shift register first chip upon completion of the transmission. What I don't know yet is how the Cyclone V SPI hardware shifts out that data. If it sends bit 0 first then we are in sync, but if it first sends out bit 7 on MOSI then my bits are flipped back to front. I suspect that it is sending 7 out first, since the SPI protocol mentions sending the most significant bit first and that would be bit 7. 

Some quick code inserted to flip all the bits didn't produce any better result that before. I think it is time to verify the basic signals are hooked up properly and behaving right - thinks like slave select and MOSI, reset and command/data mode. 

Plan G to deal with the SPI complications communicating with the LCD and touch screen

WORD SIZE FOR SPI VERSUS WHAT IS SENT TO LCD AND TOUCH CONTROLLERS

The LCD controller chip is sent one of three sequences of bits - a single byte as a command, a 16 bit word, and a sequence of contiguous 16 bit words. These are delimited by the slave select line which is active at the beginning and then deasserted after 8, 16 or n*16 bits. The touch controller always has 24 bits in a transmission, delimited by slave select active at the start and switched off after the 24th bit. 

This means that we should be using 8 bit transmissions at the SPI master in my board. We right justify the 8 bits in a 16 bit register to send or receive data. To send 16 we would write two bytes sequentially right justifying each, 2*n for n 16 bit words. The touch screen would have three bytes sequentially pushed into the register, right justified. 

Parenthetically, the LCD controller only uses all 16 bits of a word when it is loading data as pixel values to display. When taking commands or parameters to commands, it only looks at the bottom 8 bits of what is transmitted. For commands, we send only 8 and drop select, but for the parameters we send 16 bits, the actual 8 bit value right justified in that word, then drop select. 

This is done for code compatibility for when we are sending pixel data. Pixels are transmitted one 16 bit word each, with five bits of red level, six bits of green level and five bits of blue level in that word. For convenience they transmitted parameters as 16 bits but it would have worked fine, I believe, to send just 8 bits and drop select. I can only assume other devices supported by this library may have used more than 8 bits for parameters otherwise this design choice doesn't make sense.

SLAVE SELECT CONTROL TO MEET NEEDS OF CONTROLLERS

The challenge is that our SPI master will insist on dropping slave select after every byte is transmitted. That will NOT work with the shift register approach for the LCD controller nor with the touch controller. The solution is to manually control the slave select lines, ignoring the signals generated by the SPI master.

To do this, I added two signals to the PIO output block in my FPGA. By sending a 0 to bit positions 2 or 3, I can assert the slave select line for the LCD and touch controller respectively. Sending a 1 turns off the slave select once we sent our 8, 16, n*16 or 24 bit transmission. 

TESTING THE COMMUNICATIONS CORRECTNESS

I will modify the programs so that I do a minimal transmission of each length to the appropriate controller chip, choosing a sequence that will give me confirmation of successful reception. I have a command for the LCD controller chip which returns some device identifying data - this is a good first test. The touch controller can be asked to send various types of data back, which I can view to determine that it worked properly. 

A transaction which returns the ID of the LCD controller chip:

  • turn on slave select
  • set the Command/Data signal to command
  • transmit xD3 to the LCD controller chip
  • set the Command/Data signal to data
  • send two16 bit words of x0000
  • drop slave select
What will be returned is four bytes during the data transfer. The first byte is dummy and can be ignored. The next three bytes returned should be x00, x94 and x88 in order to believe we have a good communication path with the LCD controller. 

If I send a command of x90 to the touch controller followed by two bytes of x00, it will return the 12 bit ADC value during parts of the second and third byte transfers. This value will be the Y value of where the stylus is touching on the screen. By moving the stylus I can be certain that the communications with the touch controller is working properly. 

The final test will be sending a single command byte to turn off the display, once it is initialized to all pixels on by the existing code. This is done by:

  • turn on slave select
  • set Command/Data to command (value 0)
  • send x22
  • turn off slave select
When this works, we will have tested all the modes and can move on to debugging the specific codes we are transmitting to the two controllers. 

RESULTS OF THE TEST

First I reran the existing test application after switching over to the 8 bit word frame and manual slave select scheme. I hung up trying to write to the LCD controller which I realized was due to my failure to turn on both the actual slave select of the SPI module as well as the manual one I control through PIOout bits.

I can see that I am transferring data with the SPI master showing appropriate status as I write an 8 bit word frame. The LCD panel did not light up but I am feeling signs of progress and will keep testing from this point until I get everything debugged. 

One potential issue would be the shift out and in order between the SPI master and the slave devices. If I don't get a good response to one of the simple tests below, I might try sending the same stream with the bits flipped end for end. 

I then whipped up the three simple tests described above and executed the two of them that I could - the single command to blank pixels is predicated on the screen having been lit up. I was however able to send the sequences to interrogate the LCD controller ID and to measure the Y coordinate of a touch. 

Whether I sent to the touch controller or the LCD controller, whether I reversed the bits or not, I always got back zeros but the SPI master believed it was correctly transmitting what I sent. Time to devise some deeper experiments and diagnostic output to help me figure this out.

Sunday, June 4, 2023

More complications of the nonstandard pretend SPI used with the LCD Module

WORD FRAME SIZE AND SLAVE SELECT FOR LCD CONTROLLER

As previously reported, communicating with the LCD controller chip required words of 16 bits, so that the SPI master on my board does not drop slave select until the end of that transfer. Some transfers to the LCD controller involve multiple 16 bit words, which it appears would work properly even with slave select toggled between words. However, this is not absolutely certain. 

TOUCH CONTROLLER WORD FRAME SIZE AND SLAVE SELECT

The touch controller chip requires frames of 24 bits under a single activation of the slave select to that chip. The SPI master on my board will toggle slave select after the first 16 and then send a full additional 16 bits as a second transaction. Thus the current setting I have for SPI will NOT work properly with the touch controller. 

Further, there is no configuration option for 24 bit words. I would need to instead revert to the kludge where I select SPI mode 2 instead of the actual mode 0, then invert the clock to allow the touch controller on mode 0 to communicate with the master on mode 2. With word size set to 8 bits, this will allow me to send multiples of 8 bits. 

The only advantage of this is that it removes the automatic drop of slave select after each word frame. Instead, slave select will go low when the word is complete and the transmit FIFO has no more words to send. Thus if I push three bytes into the FIFO we get a 24 bit transmission under one slave select, while if I push two bytes in the FIFO I get a 16 bit transmission in a single slave select. I could even handle the mode where multiple 16 bit words are sent without dropping slave select in between. 

A second option is to use the second SPI master on my board to communicate with the touch controller while the original one speaks only to the LCD controller. This has the difficulty that I will be sharing one set of wires for SCLK, MOSI and MISO which won't work well. Had I the ability to direct wire a separate clock and data lines to the touch controller, this would have been okay.

A third option, assuming we do the kludge with inverted clock for SPI mode 2, is that I can stop and reconfigure the SPI master each time I switch between LCD and touch controller - set 16 bit words for the LCD controller and 8 bit words for the touch pad. In that way I could also implement the different speeds that the demo code had implemented, using 2.5MHz for the touch controller and 20MHz for the LCD controller communications. 

I frankly am not sure how this is supposed to work properly on Arduino, which is listed as a secondary microcontroller to drive the LCD module. Perhaps the do bit banging or some other atrocity in the Arduino side library to overcome these oddities in the implementation. 

Time for me to cogitate, in addition to regretting the day that I selected and bought this LCD Module for the project based on vague marketplace statements that it uses SPI and came with example code.