# PIC32 Drivers for ILI9486L and HX8347G TFT Controllers

## Introduction

This post builds upon the previous one, and expounds some of the details of the communication interface between the PIC32 Parallel Master Port module and LCD panel controllers – ILI9486L and HX8347G.

## Implementation

Both the display controllers support the 16 bit Intel 8080 Mode with 16BPP. The Intel 8080 mode defines 4 control lines in addition to the 16 bit Data Bus and that is what I am using. The control lines are – RDS (Read Strobe, WRS (Write Strobe), Data/Command (D/C#) Select (also called Register Select). As is evident from the names, the Read and Write strobes are used to latch the data on the bus. So to Write data on the bus, the PMP loads data (D0 – D16) and then pulls the WRS line low, when the WRS is pulled High, the display controller latches the data on the bus. Similarly for a Read, the Host PMP pulls the RDS line Low, the controller outputs data on the bus and the host reads this data on the RDS Low to High transition. The D/C# line is used to indicate to the controller whether the master is sending a command or writing/reading data.

If you are using the PIC32′s PMP, the RDS and WRS strobes are generated automatically by the hardware when you Read and Write the PMP data register. Only the D/C# and CS lines need to be generated in the driver. Typical Write and Read operations with the PMP looks like this:

The next task is to write a pixel in the display controller GRAM. HX8342 defines the following table for writing pixel data in the 16 bit mode:

What this indicates is that the color depth is controlled by setting the register 0x17 to 3, 5 6 or 7. We use 65K so we set it at 0x05. The command 0x22 is the RAMWR command which should be followed with the 16BPP data. The pixel address is set by manipulating the Start Column and Start Page registers as mentioned in the introductory post. So PutPixel on HX8347 looks like this:

This can be extended to implement GetPixel and so on. In the case of IL9486 the SC/SP values are stored in one register, so you just need to send one command followed by the “parameters”. PutPixel looks like this:

Finally, the display orientation depends on the setting of some bits usually denoted by MX, MY and MV. You should be able to see their significance from your controller datasheet..

Source code is here: HX8347G ILI9486L

# A Quick and Dirty Real-time Digital (IIR/FIR) Filter Implementation

## Introduction

You have this Data Acquisition System that coughs out data in real time, and you want to add a digital filter that takes each filter sample, throws out the filtered output. That’s the task of this post.

Let’s say the digital data is over your computer’s serial port, and you have set up some Matlab code to plot it already, now we need to filter each sample before storing it for plotting.

First of all you need to decide what kind of filter you want to use – low pass/bandpass etc, butterworth/elliptic etc, the filters order, cutoff frequency etc. And depending on all that use the matlab functions like butter(), ellip() to get the coefficients of the filter you want to use. You could calculate the coefficients by any other method also. This post assumes that you already have the filter coefficients and you just need some simple code to implement the filter.

Now that you have the coefficients usually denoted by the vectors a and b for the denominator and numerator respectively, let’s look at the general form of an IIR filter

Make sure that in your coefficients, $a(0) = 1$.

Use the following code to implement the above filter:

That’s all to it! Now consider an FIR filter, this is easier because now we do not have the vector a , so just delete the Multiply and accumulate loop for the a terms in the above code.

A moving average filter can also be implemented in a similar fashion. The code looks like this:

Obviously, the same code can be used in any other language like C, or C# if you want to do analysis using them. If this implementation does not seem to be obvious from the equation, it’s because this is a Direct-Form Transpose II implementation. An advantage with this is that you only need to use one buffer to store intermediate results. In the more-straightforward Direct-Form Transpose I implementation, you would need two buffers - one for the numerator terms and another for the denominator terms.

# Real Time Plotting With Matlab

## Introduction

The need to plot (and filter) digital data from a sensor or front end circuit is ubiquitous in embedded systems. It’s always good to plot/filter/process the data in the same environment, so it’s always good to plot data in Matlab (if you have access to it). This post will talk about how to write a simple .m file to read data from the serial port of a PC and plot it onto a figure. We will do this in “real-time”, kind of like how an oscilloscope does.

## Implementation

I assume that you already have a microcontroller or something else that will sample the analog signal you want to plot, convert the HEX values into ASCII and send it over a UART/RS232 interface to your PC. The problem this post addresses is capturing this data from Matlab and plotting it continuously.

The capture part is really straight forward, you just have to create a serial port object, open it and perform fread() on it, like shown below:

Once you get the data into matlab using fread(), the next problem is plotting this data using plot(). By default, plot() clears old data in the figure and re-draws the figure at every call. To avoid this and to have plot() append data you need to set hold on

Now you have a graph that is updated in real time, with each sample. This might be good enough if your sampling rate is slow (a few 100mS or so); but for a faster sampling rate (mine was 4mS) it is too slow and soon my PC started catching fire. More importantly, the real strength of Matlab/Octave lies in vector operations – and it really does well in handling large chunks of data.

So to improve the performance, we modify the design to fread()’ 1 second worth of samples and plot all of that data in one shot, every second. Further, to create an oscilloscope effect, one screen will display X seconds of data; after that the screen will be refreshed and another X seconds are displayed 1s at a time. This goes on for Y number of times.

Now ideally, you want Y to be infinite, and the capture should only stop when you press a button or something. So we add a callback function myCallback for the WindowButtonDownFcn event to cause the capture to stop when you click on the plot figure with your mouse.

## Notes

While debugging my code I encountered a few problems:

• If for some reason, your script breaks and you are not able to close the serial port, the next time when you try to run the script you will get a port open error. One way to solve this is the execute the commands

at the begining of the script.

• If matlab does not receive data on the serial port, the object times out and you get a warning. You could catch this by something like:
• It is also faster to have calculate the X and Y scales statically instead of using

With that you should have a nice real time plotter working as in this video. The next step is to add on-the-fly filtering.

The code for the plotter is here. Each input data sample is assumed to be in the form +xxxx- where xxxx are any hex character in ASCII. For example the data samples of 0x123F and 0xD278 would be sent as +123F-+D278- .. and so on.

# One Minute Introduction to Graphics TFT LCDs for Embedded Folks

Inspired by Jan Axelson’s One minute USB, I have decided to jot down one minute notes for other ridiculously complicated stuff that I deal with every once in a while. First in the series is a TFT LCD note.

1. A TFT LCD is made up of X x Y number of pixels, each pixel is made up of 3 segments (Red/Green/Blue). The number of bits allocated to R/G/B segments depends on how many bits per pixel (BPP) the display supports. Common formats are 8, 9, 16 and 18 BPP.

2. Displays can be a bare (RAM-less) glass or it can come with built-in a graphics controller with internal RAM. So the maximum size of display supported by a controller depends on how much RAM it has. For example a controller with 345600 Bytes RAM can support a resolution of 320 x 480 with 18 BPP.

3. These built-in display controllers generally support a variety of interface “communication” modes. Common formats are 16/8 bit “MCU mode” (also called “System Bus”), which actually means the good old Intel 8080 or Motorolla 6800 parallel bus interface and Serial bus mode(s) (like an SPI using 3 and/or 4 wires). The controller also usually supports a self-abnegating, masochistic mode called RGB mode of operation. In this mode the display controller ceases to exist and allows you to drive the display externally as if it were a bare glass. Which also happens to be what you need to do if your display does not have an controller. You have to provide frame information (HSYNC, VSYNC, Data, CLK..) over the bus. The RGB mode is useful if you are using another external graphics controller (that has more features than the built-in controller) or you want to be flexible to changing the display glass, and perhaps also for lower cost. However, do note that before you enter RGB mode, you need to configure some of the controllers registers with appropriate parameters, and you have to do this using one of the above “communication” modes. The serial modes would be most efficient for this since the data to be transferred is small and need only be sent once on initialization. You can choose which communication mode to use by setting a couple of pins in the display interface high or low.

4. The color depth of the display depends on the BPP. For instance if you have 18BPP, the color depth is 2 * exp(6+6+6) = 262k colors (assuming 6 bits each for Red, Green and Blue). And if it’s a 1BPP then you can only have 8 colors. 16BPP gives 65k color and this is the most common scheme used, since it can fit nicely into a 16 or 8 bit parallel bus.

5. The initialization code for a display controller is generally provided by the manufacturer of the display glass and is application/controller specific. However there seem to be some common features across all controllers. For example the addressing of pixels usually have row and column start and end pointers, so in practice it’s not too difficult to write your own init code if you refer some similar controller’s code.

6. The modus operandi to write a pixel into an arbitrary location in RAM is to a) set Column and Row address pointers (SC,SP) to the (x,y) co-ordinates you want to write the pixel to b) write the 16 bit pixel value to the controller memory Repeat step b) for all the contiguous pixels you want to update. The approach is similar to Read a pixel, only difference being that write control signals are changed to Read signals.

In the next post I will illustrate these concepts with PIC32′s PMP module and two display controllers – ILI9486 and HX8347G.

# A Simple I2C Driver for PIC32, PIC24 and PIC18

## Introduction

The Microchip I2C drivers and their APIs that ship with the MPLAB compiler are almost impossible to debug or understand. For some unfathomable reason, they have distributed the I2C access code in 10 (or more) different files with 5 lines of code each. So I’ve managed to put together a simple (and what I consider to be intuitive) driver. I have tested it with different slaves on PIC18, PIC24 and PIC32, and it seems to work seamlessly with only a change in .h file #defines for PIC24 and PIC32, while for PIC18 some register names are different.

Before you start, you should be aware that the PIC I2C engine cannot queue commands. So you have to wait in software for each command to be completed before issuing the next one. For example, you issue the start condition command then wait till the engine is not busy before issuing the next command.

## Details

The driver implements the following interfaces:

• Reading from the I2C peripheral:

This Writes the Regiser Number (reg) on to the slave, and then issues continuous Reads for a total of len times. Typically the slave will just have one byte of data per resister, in which case you just have to pass len = 1. If the slave stores more than one byte in a perticular “register” location, you can read out that too. All the data is copied to the rxPtr. slave_adr` is the 7-bit I2C address of the slave device. Internally, the function also waits for some time (100 iterations of a loop) for the slave to generate an ACK, in case it is slow to respond. You can modify this to suit your peripheral.

• Writing to the I2C peripheral

Write is a bit simpler than the Read. You write the resigter number you want to write to, wait and repeat if there is no ACK. Once you get an ACK, just dump the data byte by byte on the poor old slave.

For most I2C slaves, this is all the access you need.

To port the driver, change the register mapping section in the .h file, along with the Slave address, and then configure the correct baud rate. These sections are highlighted below:

The code can be downloaded here. The PIC18 driver includes code to communicate with MLX90614 Infra Red Temperature Sensor and implements the SMBus protocol including the calculation of CRC. So you can use it to modify all of the MLX registers, not just read temperature.

An example of the usage is:

# A Simple Embedded Timer Pattern

## Introduction

One of the first things I do when I’m programming a new Microcontroller is to set up a timer for the system. Once you have the timer registers properly configured, the next problem is to measure time intervals, and worrying about overflows. The following pattern is the most elegant way of measuring timer intervals without giving you a headache that I have ever seen, and I reuse it all the time!

## Problem

Need a method of measuring time intervals for all kinds of application modules. Simple time stamp difference does not work if the timer overflows.

## Prerequisite

You have configured your (hardware) timer to generate a periodic interrupt every X seconds (or milli seconds or whatever). Choose the tick so that it provides at least the smallest resolution you need for your system.

## Solution

1. Inside the timer interrupt, increment a unsigned global variable, let’s call it FreeRunningCounter.

2. To measure time difference, simply take a Time Stamp of the FreeRunningCounter at the start of the activity. The difference between the TimeStamp and the current FreeRunningCounter modulo the width of the hardware timer is the time elapsed. This will work so long as the measured period is less than or equal to the full range of FreeRunningCounter.