<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Graphics &#8211; IoT Expert</title>
	<atom:link href="https://iotexpert.com/category/tools/graphics/feed/" rel="self" type="application/rss+xml" />
	<link>https://iotexpert.com</link>
	<description>Engineering for the Internet of Things</description>
	<lastBuildDate>Thu, 20 Feb 2020 11:42:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://iotexpert.com/wp-content/uploads/2017/01/cropped-Avatar-32x32.jpg</url>
	<title>Graphics &#8211; IoT Expert</title>
	<link>https://iotexpert.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>MBED OS &#038; CY8CKIT_062S2_43012 &#038; Segger emWin &#038; NTP</title>
		<link>https://iotexpert.com/mbed-os-cy8ckit_062s2_43012-segger-emwin-ntp/</link>
					<comments>https://iotexpert.com/mbed-os-cy8ckit_062s2_43012-segger-emwin-ntp/#comments</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 23 Sep 2019 12:00:31 +0000</pubDate>
				<category><![CDATA[CY8CKIT-062S2-43012]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[MBED OS]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=7890</guid>

					<description><![CDATA[Summary Have you ever wondered about the nature of time?  Given the demographics of my readers I am quite sure that all of you have pondered this topic.  In this article I will solve one of the great mysteries of human kind.  What time is it?  Well that may be a little bit over dramatic [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>Have you ever wondered about the nature of time?  Given the demographics of my readers I am quite sure that all of you have pondered this topic.  In this article I will solve one of the great mysteries of human kind.  What time is it?  Well that may be a little bit over dramatic <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" />  Actually what I will show you is how to use the CY8CKIT-062S2-43012 development kit to get time from the internet using the Network Time Protocol (NTP), update the PSoC 6 RTC and display it on the CY8CKIT-028-TFT using MBED OS.</p>
<p>Unfortunately I will not show you a beautiful way to convert UTC to Eastern Time because I don&#8217;t actually know what that way would be which is very frustrating.  Every way that I know requires me to drag a lot of crap into my PSoC6 which I don&#8217;t really want to do.</p>
<p><a href="https://iotexpert.com/?attachment_id=7895" rel="attachment wp-att-7895"><img fetchpriority="high" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0811-1024x736.jpg" alt="" width="1024" height="736" class="alignnone size-large wp-image-7895" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0811-1024x736.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0811-600x431.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0811-300x216.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0811-768x552.jpg 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<p>For this article I will discuss:</p>
<ol>
<li>MBED OS Project Setup</li>
<li>MBED OS Event Queues</li>
<li>The RTOS Architecture</li>
<li>The Display Function(s)</li>
<li>The NTP Thread</li>
<li>The WiFI/Main Thread</li>
<li>The Whole Program</li>
</ol>
<h1>Project Setup: Create and Configure Project + Add the Libraries</h1>
<p>You should start this project by creating a project by running &#8220;mbed new NTPDemo&#8221; or by using mbed studio to create a new project.  To run this project requires at least mbed-os-5.13.3.  You have two basic choices to get the latest mbed.  For some reason which I don&#8217;t totally understand when you run mbed new it gives you a slightly older version of mbed-os.  To get a new version you can either &#8220;cd mbed-os ; mbed update mbed-os-5.13.3&#8221; or to get the latest &#8220;cd mbed-os ; mbed update master&#8221;.</p>
<p>In this project I use three libraries, emWin, the IoT Expert ST7789V library (for the display) and the ntp-client library.  To add them run</p>
<ul>
<li>mbed add <a href="https://github.com/cypresssemiconductorco/emwin.git">https://github.com/cypresssemiconductorco/emwin</a></li>
<li><span>mbed add <a href="https://github.com/ARMmbed/ntp-client.git">https://github.com/ARMmbed/ntp-client/</a></span></li>
<li>mbed add <a href="https://github.com/iotexpert/mbed-os-emwin-st7789v" target="_blank" rel="noopener noreferrer">https://github.com/iotexpert/mbed-os-emwin-st7789v</a></li>
</ul>
<p>The emWin library requires that you tell emWin about which version of the library .a to link with.  You can do this by adding this to the mbed_app.json</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">{
    "target_overrides": {
        "*": {
            "target.components_add": ["EMWIN_OSNTS"]
        }
    }
}
</pre>
<h1>MBED OS Event Queues</h1>
<p>For this project I will use one of the cool RTOS mechanisms that is built into MBED OS,  the &#8220;<a href="https://os.mbed.com/docs/mbed-os/v5.13/apis/eventqueue.html" target="_blank" rel="noopener noreferrer">EventQueue</a>&#8220;.   There is a nice tutorial in the MBED OS <a href="https://os.mbed.com/docs/mbed-os/v5.13/tutorials/the-eventqueue-api.html">documentation</a>.  An EventQueue is a tool for running a function &#8220;later&#8221; and in a different thread context.  What does that mean?  It means that there is a thread that sits around waiting until you tell it to run a function.  You tell it to run the function by pushing a function pointer into it&#8217;s EventQueue.  In other words, an EventQueue is a thread that waits for functions to be pushed into queue.  When the function is pushed into the queue it runs it.</p>
<p>How is this helpful?  There are a several of reasons.</p>
<ul>
<li>If you are in an ISR it allows you to defer execution of something to the main program.</li>
<li>It can be used to serialize access to some resource &#8211; in my case the display.</li>
<li>It allows you to schedule some event to happen regularly</li>
</ul>
<p>When MBED OS starts it automatically creates two of these event queues one of the queue threads runs at &#8220;osPriorityNormal&#8221; and can be accessed via mbed_event_queue();  The other event queue runs at &#8220;osPriorityHigh&#8221; and can be accesed by <span>mbed_highprio_event_queue();  For some reason (which I don&#8217;t understand) these queues are documented on a separate <a href="https://os.mbed.com/docs/mbed-os/v5.13/mbed-os-api-doxy/mbed__shared__queues_8h_source.html" target="_blank" rel="noopener noreferrer">page</a>.</span></p>
<h1>The RTOS Architecture</h1>
<p>Here is a picture of the architecture of my program.</p>
<p>&nbsp;</p>
<p><a href="https://iotexpert.com/?attachment_id=7914" rel="attachment wp-att-7914"><img decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4-1024x445.png" alt="" width="1024" height="445" class="alignnone size-large wp-image-7914" srcset="https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4-1024x445.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4-600x261.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4-300x130.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4-768x334.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/rtosarch-4.png 1089w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>The Main Thread</h1>
<p>The main function which is also the main thread, which then becomes the WiFi Thread</p>
<ol>
<li>Initializes the GUI</li>
<li>Starts up the Display Event Queue</li>
<li>Turns on the WiFi and attaches a callback (to notify the program of WiFI Status Changes)</li>
<li>Try&#8217;s to connect to the WiFi Network</li>
<li>If it fails, it updates the display and try&#8217;s again after 2 seconds</li>
<li>Once it is connected it starts up the NTP Server Thread</li>
<li>And then waits for the WiFi semaphore to be set&#8230; which only happens if WiFi gets disconnected at which point it goes back to the start of the WiFI connection and try again.</li>
</ol>
<pre class="start-line:133 EnlighterJSRAW" data-enlighter-language="c" ">int main()
{
    int wifiConnectionAttempts;
    int ret;

    GUI_Init();
    displayQueue = mbed_event_queue();
    displayQueue-&gt;call_every(1000, &amp;updateDisplayTime);

    wifi = WiFiInterface::get_default_instance();
    wifi-&gt;attach(&amp;wifiStatusCallback);

   while(1)
   {
       wifiConnectionAttempts = 1;
        do {

            ret = wifi-&gt;connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2);
            displayQueue-&gt;call(updateDisplayWiFiConnectAttempts,wifiConnectionAttempts);

            if (ret != 0) {
                wifiConnectionAttempts += 1;
                wait(2.0); // If for some reason it doesnt work wait 2s and try again
            }
        } while(ret !=0);

        // If the NTPThread is not running... then start it up
        if(netTimeThreadHandle.get_state() == Thread::Deleted)
            netTimeThreadHandle.start(NTPTimeThread);
 
        WiFiSemaphore.acquire();
   }</pre>
<h1>Display Event Queue</h1>
<p>Display EventQueue is used to run functions which update the display.  By using an EventQueue it ensure that the Display updates happen serially and there are no display resource conflicts.  The four functions are</p>
<ol>
<li>updateDisplayWiFiStatus</li>
<li>updateDisplayWifiConnectAttempts</li>
<li>updateDisplayNTPCount</li>
<li>updateDisplayTime</li>
</ol>
<p>I wanted a function which could display the state of the WiFi connection on the screen.  This is a string of text which is generated in the connection status function.  In order to send the message, the connection status function will &#8220;malloc&#8221; which then requires the updateDisplayWiFiStatus function to free the memory associated with the message.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">#define DISP_LEFTMARGIN 10
#define DISP_TOPMARGIN 4
#define DISP_LINESPACE 2
// updateDisplayWiFiStatus
// Used to display the wifi status
void updateDisplayWiFiStatus(char *status)
{
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringAt(status,DISP_LEFTMARGIN, DISP_TOPMARGIN); 
    free(status);  
}
</pre>
<p>When I started working on this program I had a bug in my connections so I added the ability to tell how many WiFI connections attempts had happened.  I also wondered how many times there might be a disconnect if I ran this program a long time.  The answer is I ran it for two days and it didn&#8217;t disconnect a single time.  This function simply takes a number from the caller and displays it on the screen.  Notice that I use snprintf to make sure that I don&#8217;t overrun the buffer (which I doubt could happen because I made it 128 bytes).</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">// updateDisplayWiFiConnectAttempts
// This function displays the number of attempted connections
void updateDisplayWiFiConnectAttempts(int count)
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"WiFi Connect Attempts = %d",count); 
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringAt(buffer,DISP_LEFTMARGIN, DISP_TOPMARGIN + (GUI_GetFontSizeY()+DISP_LINESPACE) ); 
}
</pre>
<p>I was curious how many times the NTP connection would happen.  So I added the ability to display a count.  Notice that I use a static variable to keep track of the number of times this function is called rather than pushing the number as an argument.  Perhaps this is a design flaw?</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">// updateDisplayNTPCount
// updates the display with the number of time the NTP Server has been called
void updateDisplayNTPCount(void)
{
    static int count=0;
    char buffer[128];
    count = count + 1;
    snprintf(buffer,sizeof(buffer),"NTP Updates = %d\n",count);
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringHCenterAt(buffer,LCD_GetXSize()/2,LCD_GetYSize() - GUI_GetFontSizeY()); // near the bottom
}
</pre>
<p>The main display function is the seconds which is displayed in the middle of the screen.  I get the time from the RTC in the PSoC and is set by the NTP Server.  Notice my rather serious hack to handle the Eastern time difference to UTC&#8230; which unfortunately only works in the Summer.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">// updateDisplayTime
// This function updates the time on the screen
void updateDisplayTime()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [128];

  time (&amp;rawtime);
  rawtime = rawtime - (4*60*60); // UTC - 4hours ... serious hack which only works in summer

  timeinfo = localtime (&amp;rawtime);
  strftime (buffer,sizeof(buffer),"%r",timeinfo);
  GUI_SetFont(GUI_FONT_32B_1);
  GUI_DispStringHCenterAt(buffer,LCD_GetXSize()/2,LCD_GetYSize()/2 - GUI_GetFontSizeY()/2);
}</pre>
<h1>NTP Time Thread</h1>
<p>The <a href="https://en.wikipedia.org/wiki/Network_Time_Protocol" target="_blank" rel="noopener noreferrer">Network Time Protocol</a> was invented in 1981 by <a href="https://www.eecis.udel.edu/~mills/" target="_blank" rel="noopener noreferrer">Dr. David Mills</a> for use in getting Internet connected computers to have the right time.  Since then it has been expanded a bunch of times to include Cellular, GPS and other networks.  The scheme includes methods for dealing with propogation delay etc.  However, for our purposes we will just ask one of the NIST computers, what time is it?</p>
<p>The way it works is that you setup a structure with 48 bytes in it.  Then you open a UDP connection to an NTP server (which NIST runs for you) then it will fill out the same structure with some time data and send it back to you.  Here is the packet:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">typedef struct
{

  uint8_t li_vn_mode;      // Eight bits. li, vn, and mode.
                           // li.   Two bits.   Leap indicator.
                           // vn.   Three bits. Version number of the protocol.
                           // mode. Three bits. Client will pick mode 3 for client.

  uint8_t stratum;         // Eight bits. Stratum level of the local clock.
  uint8_t poll;            // Eight bits. Maximum interval between successive messages.
  uint8_t precision;       // Eight bits. Precision of the local clock.

  uint32_t rootDelay;      // 32 bits. Total round trip delay time.
  uint32_t rootDispersion; // 32 bits. Max error aloud from primary clock source.
  uint32_t refId;          // 32 bits. Reference clock identifier.

  uint32_t refTm_s;        // 32 bits. Reference time-stamp seconds.
  uint32_t refTm_f;        // 32 bits. Reference time-stamp fraction of a second.

  uint32_t origTm_s;       // 32 bits. Originate time-stamp seconds.
  uint32_t origTm_f;       // 32 bits. Originate time-stamp fraction of a second.

  uint32_t rxTm_s;         // 32 bits. Received time-stamp seconds.
  uint32_t rxTm_f;         // 32 bits. Received time-stamp fraction of a second.

  uint32_t txTm_s;         // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
  uint32_t txTm_f;         // 32 bits. Transmit time-stamp fraction of a second.

} __PACKED ntp_packet_t;              // Total: 384 bits or 48 bytes.</pre>
<p>The code to send the packet is really simple.  The only trick is that when you send data on the network you almost always use big endian, so you need to use the function nthol to convert.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">void NTPClient::set_server(char* server, int port) {
    nist_server_address = server;
    nist_server_port = port;
}

time_t NTPClient::get_timestamp(int timeout) {
    const time_t TIME1970 = (time_t)2208988800UL;
    int ntp_send_values[12] = {0};
    int ntp_recv_values[12] = {0};

    SocketAddress nist;

    if (iface) {
        int ret_gethostbyname = iface-&gt;gethostbyname(nist_server_address, &amp;nist);

        if (ret_gethostbyname &lt; 0) {
            // Network error on DNS lookup
            return ret_gethostbyname;
        }

        nist.set_port(nist_server_port);

        memset(ntp_send_values, 0x00, sizeof(ntp_send_values));
        ntp_send_values[0] = '\x1b';

        memset(ntp_recv_values, 0x00, sizeof(ntp_recv_values));

        UDPSocket sock;
        sock.open(iface);
        sock.set_timeout(timeout);

        sock.sendto(nist, (void*)ntp_send_values, sizeof(ntp_send_values));

        SocketAddress source;
        const int n = sock.recvfrom(&amp;source, (void*)ntp_recv_values, sizeof(ntp_recv_values));

        if (n &gt; 10) {
            return ntohl(ntp_recv_values[10]) - TIME1970;
</pre>
<p>The times in the structure are represented with two 32-bit numbers</p>
<ul>
<li># of seconds since 1/1/1900 (notice this is not 1970)</li>
<li># of fractional seconds in 1/2^32 chunks (that ain&#8217;t a whole lotta time)</li>
</ul>
<p>The four numbers are</p>
<ul>
<li>Reference Time &#8211; when you last sent a packet</li>
<li>Origin Time &#8211; when you sent the packet (from your clock)</li>
<li>Receive Time &#8211; when the NTP server received your packet</li>
<li>Transmit Time &#8211; when your NTP server sent the packet back to you</li>
</ul>
<p>You know when you send the packet &#8211; called T1.  You know when you received the packet &#8211; called T4.  You know when the other side received your packet &#8211; called T2 and you know when the other side sent the packet called T3.  With this information you can calculate the network delay, stability of the clocks etc.  However, the simplest thing to do is to take the transit time, which is in UTC, and set your clock assuming 0 delay.</p>
<p>In MBEDOS to set the RTC clock in the PSoC you call the function with the number of seconds since 1/1/1970.  Don&#8217;t forget that the time that comes back from NTP is in seconds since 1/1/1900.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">                set_time(timestamp);
</pre>
<p>Given that the PSoC 6 RTC counts in seconds you can just ignore the partial seconds.</p>
<h1>WiFi Semaphore</h1>
<p>At the top of main I registered to WiFi that I want a callback when the state of the WiFi changes.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">    wifi-&gt;attach(&amp;wifiStatusCallback);
</pre>
<p>This function does two things.</p>
<ul>
<li>Updates the screen as the state goes from unconnected to connected</li>
<li>Unlocks a semaphore to tell the main thread to reconnect.</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">// wifiStatusCallback
// Changes the display when the wifi status is changed
void wifiStatusCallback(nsapi_event_t status, intptr_t param)
{
    const int buffSize=40;
    char *statusText;
    statusText = (char *)malloc(buffSize);

    switch(param) {
        case NSAPI_STATUS_LOCAL_UP:
            snprintf(statusText,buffSize,"WiFi IP = %s",wifi-&gt;get_ip_address());
            break;
        case NSAPI_STATUS_GLOBAL_UP:
            snprintf(statusText,buffSize,"WiFi IP = %s",wifi-&gt;get_ip_address());
            break;
        case NSAPI_STATUS_DISCONNECTED:
            WiFiSemaphore.release();
            snprintf(statusText,buffSize,"WiFi Disconnected");
            break;
        case NSAPI_STATUS_CONNECTING:
            snprintf(statusText,buffSize,"WiFi Connecting");
            break;
        default:
            snprintf(statusText,buffSize,"Not Supported");
            break;
    }
    displayQueue-&gt;call(updateDisplayWiFiStatus,statusText);
}</pre>
<h1>The Whole Program</h1>
<p>Here is the whole program.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#include "mbed.h"
#include "GUI.h"
#include "mbed_events.h"
#include "ntp-client/NTPClient.h"

Thread netTimeThreadHandle;

WiFiInterface *wifi;
EventQueue *displayQueue;
Semaphore WiFiSemaphore;

/******************************************************************************************
*
* Display Functions
*
********************************************************************************************/

#define DISP_LEFTMARGIN 10
#define DISP_TOPMARGIN 4
#define DISP_LINESPACE 2
// updateDisplayWiFiStatus
// Used to display the wifi status
void updateDisplayWiFiStatus(char *status)
{
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringAt(status,DISP_LEFTMARGIN, DISP_TOPMARGIN); 
    free(status);  
}

// updateDisplayWiFiConnectAttempts
// This function displays the number of attempted connections
void updateDisplayWiFiConnectAttempts(int count)
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"WiFi Connect Attempts = %d",count); 
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringAt(buffer,DISP_LEFTMARGIN, DISP_TOPMARGIN + (GUI_GetFontSizeY()+DISP_LINESPACE) ); 
}

// updateDisplayNTPCount
// updates the display with the number of time the NTP Server has been called
void updateDisplayNTPCount(void)
{
    static int count=0;
    char buffer[128];
    count = count + 1;
    snprintf(buffer,sizeof(buffer),"NTP Updates = %d\n",count);
    GUI_SetFont(GUI_FONT_16_1);
    GUI_DispStringHCenterAt(buffer,LCD_GetXSize()/2,LCD_GetYSize() - GUI_GetFontSizeY()); // near the bottom
}

// updateDisplayTime
// This function updates the time on the screen
void updateDisplayTime()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [128];

  time (&amp;rawtime);
  rawtime = rawtime - (4*60*60); // UTC - 4hours ... serious hack which only works in summer

  timeinfo = localtime (&amp;rawtime);
  strftime (buffer,sizeof(buffer),"%r",timeinfo);
  GUI_SetFont(GUI_FONT_32B_1);
  GUI_DispStringHCenterAt(buffer,LCD_GetXSize()/2,LCD_GetYSize()/2 - GUI_GetFontSizeY()/2);
}

/******************************************************************************************
* NTPTimeThread
* This thread calls the NTP Timeserver to get the UTC time
* It then updates the time in the RTC
* And it updates the display by adding an event to the display queue
********************************************************************************************/
void NTPTimeThread()
{
    NTPClient ntpclient(wifi);

    while(1)
    {
        if(wifi-&gt;get_connection_status() == NSAPI_STATUS_GLOBAL_UP)
        {
            time_t timestamp = ntpclient.get_timestamp();
            if (timestamp &lt; 0) {
                // probably need to do something different here
            } 
            else 
            {
                set_time(timestamp);
                displayQueue-&gt;call(updateDisplayNTPCount);
            }
        }
        wait(60.0*5); // Goto the NTP server every 5 minutes
    }
}

/******************************************************************************************
*
* Main &amp; WiFi Thread
*
********************************************************************************************/

// wifiStatusCallback
// Changes the display when the wifi status is changed
void wifiStatusCallback(nsapi_event_t status, intptr_t param)
{
    const int buffSize=40;
    char *statusText;
    statusText = (char *)malloc(buffSize);

    switch(param) {
        case NSAPI_STATUS_LOCAL_UP:
            snprintf(statusText,buffSize,"WiFi IP = %s",wifi-&gt;get_ip_address());
            break;
        case NSAPI_STATUS_GLOBAL_UP:
            snprintf(statusText,buffSize,"WiFi IP = %s",wifi-&gt;get_ip_address());
            break;
        case NSAPI_STATUS_DISCONNECTED:
            WiFiSemaphore.release();
            snprintf(statusText,buffSize,"WiFi Disconnected");
            break;
        case NSAPI_STATUS_CONNECTING:
            snprintf(statusText,buffSize,"WiFi Connecting");
            break;
        default:
            snprintf(statusText,buffSize,"Not Supported");
            break;
    }
    displayQueue-&gt;call(updateDisplayWiFiStatus,statusText);
}


int main()
{
    int wifiConnectionAttempts;
    int ret;

    GUI_Init();
    displayQueue = mbed_event_queue();
    displayQueue-&gt;call_every(1000, &amp;updateDisplayTime);

    wifi = WiFiInterface::get_default_instance();
    wifi-&gt;attach(&amp;wifiStatusCallback);

   while(1)
   {
       wifiConnectionAttempts = 1;
        do {

            ret = wifi-&gt;connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2);
            displayQueue-&gt;call(updateDisplayWiFiConnectAttempts,wifiConnectionAttempts);

            if (ret != 0) {
                wifiConnectionAttempts += 1;
                wait(2.0); // If for some reason it doesnt work wait 2s and try again
            }
        } while(ret !=0);

        // If the NTPThread is not running... then start it up
        if(netTimeThreadHandle.get_state() == Thread::Deleted)
            netTimeThreadHandle.start(NTPTimeThread);
 
        WiFiSemaphore.acquire();
   }
}
</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/mbed-os-cy8ckit_062s2_43012-segger-emwin-ntp/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>MBEDOS Libraries &#038; emWin Configuration Files</title>
		<link>https://iotexpert.com/mbedos-libraries-emwin-configuration-files/</link>
					<comments>https://iotexpert.com/mbedos-libraries-emwin-configuration-files/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 02 Sep 2019 11:36:31 +0000</pubDate>
				<category><![CDATA[CY8CKIT-062S2-43012]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[MBED OS]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=7851</guid>

					<description><![CDATA[Summary I have written a fair amount about Graphics Displays, using the Segger emWin graphics library and MBED OS.  I have found it irritating to do all of the configuration stuff required to get these kinds of projects going.  I inevitably go back, look at my old articles, find the github repository of my example [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>I have written a fair amount about Graphics Displays, using the <a href="https://www.segger.com/products/user-interface/emwin/" target="_blank" rel="noopener noreferrer">Segger emWin</a> graphics library and MBED OS.  I have found it irritating to do all of the configuration stuff required to get these kinds of projects going.  I inevitably go back, look at my old articles, find the github repository of my example projects etc.  This week I wanted to write some programs for the new CY8CKIT-062S2-43012 development kit so I thought that I would try all of the Cypress displays using that development kit.  Rather than starting with example projects, this time I decided to build configurable mbedos libraries. In this article I will show you how to build configurable mbed os libraries which will allow you to use the emWin Graphics Library with all of the Cypress display shields.</p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/img_0806/" rel="attachment wp-att-7852"><img decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0806-1024x718.jpg" alt="" width="1024" height="718" class="alignnone size-large wp-image-7852" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0806-1024x718.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0806-600x421.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0806-300x210.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0806-768x538.jpg 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/img_0804/" rel="attachment wp-att-7853"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0804-1024x745.jpg" alt="" width="1024" height="745" class="alignnone size-large wp-image-7853" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0804-1024x745.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0804-600x436.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0804-300x218.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0804-768x559.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a> <a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/img_0805/" rel="attachment wp-att-7854"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0805-1024x729.jpg" alt="" width="1024" height="729" class="alignnone size-large wp-image-7854" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0805-1024x729.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0805-600x427.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0805-300x214.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0805-768x547.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>In this article I will walk you through:</p>
<ul>
<li>The CY8CKIT-032 &amp; SSD1306 Display Driver &amp; emWin</li>
<li>MBED OS Libraries</li>
<li>MBED OS Configuration</li>
<li>Configuration Overrides</li>
<li>The SSD1306 emWin Configuration</li>
<li>Using the SSD1306 Configuration Library</li>
<li>emWin Configuration Libraries</li>
</ul>
<h1>The CY8CKIT-032 &amp; SSD1306 Display Driver &amp; emWin</h1>
<p>The CY8CKIT-032 has a little 0.96&#8243; OLED display that is attached to the Salomon Systech SSD1306 Display Driver.  I have <a href="https://iotexpert.com/?s=ssd1306" target="_blank" rel="noopener noreferrer">written</a> quite a bit about this little screen as it is cheap and fairly easy to use.  It became even easier when we released the Segger emWin SPAGE display driver.  And with my new library it should be trivial to use and configure for your setup.</p>
<p>You can read in detail about the functionality <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/" target="_blank" rel="noopener noreferrer">here</a> but in short:</p>
<ul>
<li>The display driver chip is attached to the PSoC via I2C</li>
<li>You need to provide the Segger emWin driver
<ul>
<li>GUIConfig.h/cpp &#8211; Segger GUI configuration</li>
<li>LCDConf.h/cpp &#8211; Setup files for the LCD</li>
<li>GUI_X_Mbed.cpp &#8211; RTOS control functions for delays etc.</li>
<li>ssd1306.h/c &#8211; physical interface to the SSD1306 controller</li>
</ul>
</li>
<li>You need to initialize the PSoC I2C before talking to the display</li>
<li>You need to initialize the display driver chip before drawing on the screen</li>
</ul>
<p>In general all of this configuration will be the same from project to project to project.  However, you may very will find that you have the display connected to a different set of pins.  I suppose that would put all of these files into some directory.  Then you could copy that directory into your project every time.  Which would leave you with modifying the configuration to meet your specific board connection.  The problem with that is you have now deeply intertwined your project with those files.</p>
<p>MBED OS has given us a really cool alternative.  Specifically the Library and <a href="https://os.mbed.com/docs/mbed-os/v5.13/reference/configuration.html" target="_blank" rel="noopener noreferrer">configuration</a> systems.</p>
<h1>MBED OS Libraries</h1>
<p>An MBED OS library is simply a git repository.  Just a directory of source files.  When you run the command &#8220;mbed add repository&#8221; it does two basic things</p>
<ol>
<li>It does a &#8220;git clone&#8221; to make a copy of the repository inside of your project.</li>
<li>It creates a file with the repository name.lib which contains the URL to the version of the repository</li>
</ol>
<p>Here is a an MBED add of my graphics configuration library for the SSD1306</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">(mbed CLI) ~/Mbed Programs/test032 $ mbed add git@github.com:iotexpert/mbed-os-emwin-ssd1306.git
[mbed] Working path "/Users/arh/Mbed Programs/test032" (program)
[mbed] Adding library "mbed-os-emwin-ssd1306" from "ssh://git@github.com/iotexpert/mbed-os-emwin-ssd1306" at latest revision in the current branch
[mbed] Updating reference "mbed-os-emwin-ssd1306" -&gt; "https://github.com/iotexpert/mbed-os-emwin-ssd1306/#7986006c17bd572da317257640f35ec3b232414e"
(mbed CLI) ~/Mbed Programs/test032 $ ls mbed-os-emwin-ssd1306
GUIConf.cpp    GUI_X_Mbed.cpp LCDConf.h      mbed_lib.json  ssd1306.h
GUIConf.h      LCDConf.cpp    README.md      ssd1306.cpp
(mbed CLI) ~/Mbed Programs/test032 $ more mbed-os-emwin-ssd1306.lib 
https://github.com/iotexpert/mbed-os-emwin-ssd1306/#7986006c17bd572da317257640f35ec3b232414e
(mbed CLI) ~/Mbed Programs/test032 $ 
</pre>
<p>Notice that when I &#8220;ls&#8217;d&#8221; the directory that all of file required to confiugure emWin for the SSD1306 became part of my project.  And the file mbed-os-emwin-ssd1306.lib was created with the URL of the github repository.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">https://github.com/iotexpert/mbed-os-emwin-ssd1306/#7986006c17bd572da317257640f35ec3b232414e
</pre>
<p>When you run &#8220;mbed compile&#8221; the build system just searches that directory for cpp and h files turns them into .0&#8217;s and add them to the the BUILD directory.  However, before it compiles it run the configuration system.</p>
<h1>MBED OS Configuration System</h1>
<p>The configuration system takes the file &#8220;mbed_lib.json&#8221; parses it and turns it into a C-header file called mbed_config.h.  The format of this file is</p>
<ul>
<li>The name of the component &#8211; in this case &#8220;SSD1306_OLED&#8221;</li>
<li>The parameters of the component SDA, SCL, I2CADDRESS and I2CFREQ</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">{
    "name" : "SSD1306_OLED",
    "config": {
        "SDA":"P6_1",
        "SCL":"P6_0",
        "I2CADDRESS":"0x78",
        "I2CFREQ":"400000"
    }
}
</pre>
<p>This header file is then placed into the BUILD directory of your project and is included as part of #include &#8220;mbed.h&#8221;</p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/screen-shot-2019-08-24-at-10-50-52-am/" rel="attachment wp-att-7860"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM-957x1024.png" alt="" width="957" height="1024" class="alignnone size-large wp-image-7860" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM-957x1024.png 957w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM-600x642.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM-280x300.png 280w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM-768x822.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-10.50.52-AM.png 1022w" sizes="auto, (max-width: 957px) 100vw, 957px" /></a></p>
<p>If you open mbed_config.h you will find that it creates #defines of the component parameters</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#define MBED_CONF_SSD1306_OLED_I2CADDRESS                                     0x78                                                                                             // set by library:SSD1306_OLED
#define MBED_CONF_SSD1306_OLED_I2CFREQ                                        400000                                                                                           // set by library:SSD1306_OLED
#define MBED_CONF_SSD1306_OLED_SCL                                            P6_0                                                                                             // set by library:SSD1306_OLED
#define MBED_CONF_SSD1306_OLED_SDA                                            P6_1</pre>
<p>This is really nice because I can then reference those #defines in my source code.</p>
<h1>Configuration Overrides</h1>
<p>When you are building the library you can create an arbitrary number of these parameters which are then applied to all of the uses of that library.  Or if there is some reason why one target is different you can specify the parameters for that specific target by changing the mbed_lib.json.  For instance if the CY8CKIT_062S2_43012 need a 100K I2C frequency instead of 400K (it doesn&#8217;t), you could do this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">{
    "name" : "SSD1306_OLED",
    "config": {
        "SDA":"P6_1",
        "SCL":"P6_0",
        "I2CADDRESS":"0x78",
        "I2CFREQ":"400000"
    },
    "target_overrides" : {
        "CY8CKIT_062S2_43012" : {
            "I2CFREQ":"100000"
        }
    }
}
</pre>
<p>The application developer is also allowed to over-ride the parameter by providing the target overrides in the MBED OS file &#8220;mbed_app.json&#8221;.  Notice that the way you specify the parameter name is different in this file than the mbed_lib.json.  In this case you give it the name of the library.parametername.  Here is an example setting the I2CFrequency to 100K</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">{
	"target_overrides": {
        "*": {
            "target.components_add": ["EMWIN_OSNTS"]
        },
        "CY8CKIT_062S2_43012" : {
            "SSD1306_OLED.I2CFREQ": "1000000"
        }
	}
}</pre>
<p>Which would result in a change to the generated #define in mbed_config.h</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#define MBED_CONF_SSD1306_OLED_I2CFREQ                                        1000000</pre>
<p>Notice that you can specify a &#8220;*&#8221; to match all of the targets, or you can specify the exact target.</p>
<h1>The SSD1306 emWin Configuration</h1>
<p>I use the configuration system to generate #defines for the</p>
<ul>
<li>SCL/SDA Pin Numbers</li>
<li>I2C Address</li>
<li>I2C Frequency</li>
</ul>
<p>Which lets my use those #defines in ssd1306.cpp</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">I2C Display_I2C(MBED_CONF_SSD1306_OLED_SDA, MBED_CONF_SSD1306_OLED_SCL);</pre>
<p>And</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">void ssd1306_Init(void) 
{
    Display_I2C.frequency(MBED_CONF_SSD1306_OLED_I2CFREQ);
}</pre>
<h1>Using the SSD1306 Configuration Library</h1>
<p>Lets make an example project that uses the CY8CKIT_062S2_43012 and the CY8CKIT032 using the Segger graphics library and my configuration library.</p>
<p>Start by make a new project, adding the emWin library and the configuration library.  It should look something like this</p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/screen-shot-2019-08-24-at-11-39-40-am/" rel="attachment wp-att-7863"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM-1024x470.png" alt="" width="1024" height="470" class="alignnone size-large wp-image-7863" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM-1024x470.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM-600x275.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM-300x138.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM-768x352.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.39.40-AM.png 1674w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now edit the mbed_app.json to add the emWin library</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">{
	"target_overrides": {
        "*": {
            "target.components_add": ["EMWIN_OSNTS"]
        }
	}
}</pre>
<p>Create the main.cpp which simply initializes the display and displays &#8220;hello world&#8221;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#include "mbed.h"
#include "GUI.h"

int main()
{
  GUI_Init();
  GUI_SetColor(GUI_WHITE);
  GUI_SetBkColor(GUI_BLACK);
  GUI_SetFont(GUI_FONT_13B_1);
  GUI_SetTextAlign(GUI_TA_CENTER);
  GUI_DispStringAt("Hello World", GUI_GetScreenSizeX()/2,GUI_GetScreenSizeY()/2 - GUI_GetFontSizeY()/2);
}</pre>
<p>When you compile it with</p>
<ul>
<li><span>mbed compile -t GCC_ARM -m CY8CKIT_062S2_43012 -f</span></li>
</ul>
<p>You should get something like this:</p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/screen-shot-2019-08-24-at-11-43-40-am/" rel="attachment wp-att-7864"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM-1024x985.png" alt="" width="1024" height="985" class="alignnone size-large wp-image-7864" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM-1024x985.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM-600x577.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM-300x288.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM-768x738.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-24-at-11.43.40-AM.png 1664w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And your screen should look like this (notice I made the font bigger than the original screen shot)</p>
<p><a href="https://iotexpert.com/2019/09/02/mbedos-libraries-emwin-configuration-files/img_0807/" rel="attachment wp-att-7866"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0807-1024x876.jpg" alt="" width="1024" height="876" class="alignnone size-large wp-image-7866" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0807-1024x876.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0807-600x513.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0807-300x257.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0807-768x657.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>emWin Configuration Libraries</h1>
<p>Finally I created libraries for all of the Cypress displays.  You can use these to make your project easier to get going.</p>
<div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Kit</th>
<th >Driver Chip</th>
<th >Library Link</th>
</tr>
</thead>
<tbody>
<tr><td ><a href="https://www.cypress.com/documentation/development-kitsboards/tft-display-shield-board-cy8ckit-028-tft" target="_blank" rel="noopener noreferrer">CY8CKIT-028-TFT</a></td>
<td >ST7789V</td>
<td ><a href="https://github.com/iotexpert/mbed-os-emwin-st7789v" target="_blank" rel="noopener noreferrer">git@github.com:iotexpert/mbed-os-emwin-st7789v.git</a></td>
</tr>

<tr><td ><a href="https://www.cypress.com/documentation/development-kitsboards/cy8ckit-032-psoc-analog-front-end-afe-arduino-shield" target="_blank" rel="noopener noreferrer">CY8CKIT-032</a></td>
<td >SSD1306</td>
<td ><a href="https://github.com/iotexpert/mbed-os-emwin-ssd1306" target="_blank" rel="noopener noreferrer">git@github.com:iotexpert/mbed-os-emwin-ssd1306.git</a></td>
</tr>

<tr><td ><a href="https://www.cypress.com/documentation/development-kitsboards/e-ink-display-shield-board-cy8ckit-028-epd" target="_blank" rel="noopener noreferrer">CY8CKIT-028-EPD</a></td>
<td >Pervasive EPD</td>
<td > <a href="https://github.com/iotexpert/mbed-os-emwin-epd" target="_blank" rel="noopener noreferrer">git@github.com:iotexpert/mbed-os-emwin-epd.git</a></td>
</tr>
</tbody></table></div>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/mbedos-libraries-emwin-configuration-files/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Debugging SSD1306 Display Problems</title>
		<link>https://iotexpert.com/debugging-ssd1306-display-problems/</link>
					<comments>https://iotexpert.com/debugging-ssd1306-display-problems/#comments</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Wed, 07 Aug 2019 13:19:13 +0000</pubDate>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[MBED OS]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=7593</guid>

					<description><![CDATA[Summary This article explains in detail how to use and debug SSD1306 displays.  In this article, I use the Segger emWin library and MBEDOS, but for all practical purposes this discussion applies to all other interfaces to the board including Arduino, Raspberry Pi, Adafruit, etc.  I will say from the outset that I spent far [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>This article explains in detail how to use and debug SSD1306 displays.  In this article, I use the Segger emWin library and MBEDOS, but for all practical purposes this discussion applies to all other interfaces to the board including Arduino, Raspberry Pi, Adafruit, etc.  I will say from the outset that I spent far far too much time digging into the inner workings of an 11 year old graphics driver.  Oh well, hopefully someone will get some benefit.</p>
<p>A year ago (or so) I designed a user interface board called the CY8CKIT-032 to go with my Cypress WICED WiFi book and class.  This board uses a PSoC 4 Analog co-processor which can do a bunch of cool stuff.  I have a series of articles planned about that board, but that will be for another day.  One of the things that I did was put a 0.96&#8243; I2C OLED Display based on a SSD1306 driver on the board.  These displays are widely available from Alibaba and eBay for &lt;$2.  I think that the displays are being used in inexpensive cells phones in China so there are tons of them and they are CHEAP!  The bad news is that if you google &#8220;ssd1306 problems&#8221; you will find an absolute rogues gallery of unpleasantness.  It seems that tons of people struggle to get these things working.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0744/" rel="attachment wp-att-7604"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0744-1024x842.jpg" alt="" width="1024" height="842" class="alignnone size-large wp-image-7604" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0744-1024x842.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0744-600x493.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0744-300x247.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0744-768x631.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>This whole thing started last week as Cypress released and update to our MBED OS implementation.  This update included releasing a complete set of the Segger emWin drivers.  I had been wanting to step up to a more robust graphics library than the Adafruit library that I used in this <a href="https://iotexpert.com/2019/02/17/mbed-os-psoc-6-ssd1306/" target="_blank" rel="noopener noreferrer">article</a>.  I was pleased to see that our release included the emWin SPAGE driver which knows how to talk to a bunch of different page based displays including the SSD1306.</p>
<p>But, as always, I had to wrestle with the display a little bit before I got everything working.  This time I wrote down what I did/learned.  So, for this article I will describe</p>
<ul>
<li>The SSD1306 Electrical Interface</li>
<li>The SSD1306 Software Interface</li>
<li>The SSD1306 Driver Registers</li>
<li>The SSD1306 Graphics Data RAM</li>
<li>Reading from the Frame Buffer</li>
<li>My Initialization Sequence</li>
<li>Some Other Initialization Sequences</li>
<li>A Bunch of Screen Problems &amp; How To Fix</li>
</ul>
<h1>The Electrical Interface</h1>
<p>There is not a lot to know about the electrical interface.  The data sheet specifies that the device can use I2C, SPI, 6800 and 8080.  I have not seen either the 6800 or 8080 interface put onto any of these OLED displays.  Like all driver chips, the SSD1306 has an absolute boatload of pins, in fact, 281.  The chip is long and skinny and was made to be mounted either on the display under the glass or on the flex connector.  Of the 281 pins, 128+64=196 are connected to the segments and commons in the display.  The rest of the pins are either capacitors, no-connects, power/ground or data signals.  The data signals are</p>
<ul>
<li>D0-D7 either parallel data for 8080/6800 or SDA/SCL for I2C or MOSI/MISO for SPI</li>
<li>E &#8211; enable signal for 6800 or RD for 8080</li>
<li>R/W# &#8211; Read Write for 6800/8080</li>
<li>CS &#8211; Chip Select for SPI, 8080, 6800</li>
<li>D/C# &#8211; Data or Command for SPI, 6800, 8080 or Slave Address Select for I2C</li>
<li>Reset &#8211; Chip reset</li>
</ul>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-07-28-at-7-28-49-am/" rel="attachment wp-att-7632"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM-1024x281.png" alt="" width="1024" height="281" class="alignnone size-large wp-image-7632" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM-1024x281.png 1024w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM-600x165.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM-300x82.png 300w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM-768x211.png 768w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-7.28.49-AM.png 1936w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>For the I2C configurations it is common to tie the reset pin High and not bring the pin to a connector.  The SA0 is also typically connected via a 0-ohm resistor to either 0 or 1 which configures the device to have the 7-bit address 0x3C or 0x3D or 8-bit 0x78 or 0x7A.  Here is a picture of the back of one of my boards where you can see the 0ohm resistor.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0758/" rel="attachment wp-att-7633"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758-967x1024.jpg" alt="" width="967" height="1024" class="alignnone size-large wp-image-7633" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758-967x1024.jpg 967w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758-600x636.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758-283x300.jpg 283w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758-768x814.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0758.jpg 1059w" sizes="auto, (max-width: 967px) 100vw, 967px" /></a></p>
<p>Sometimes all of the data pins are available on the back of the board.  This lets you move/add/change the 0-ohm resistors to configure the mode of the chip.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/sku_340467_1-2/" rel="attachment wp-att-7636"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/sku_340467_1-1.jpg" alt="" width="479" height="455" class="alignnone size-full wp-image-7636" srcset="https://iotexpert.com/wp-content/uploads/2019/07/sku_340467_1-1.jpg 479w, https://iotexpert.com/wp-content/uploads/2019/07/sku_340467_1-1-300x285.jpg 300w" sizes="auto, (max-width: 479px) 100vw, 479px" /></a> <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/b9d2d39952c19f77d0cc89703b80c0a0-image-600x600-2/" rel="attachment wp-att-7637"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/b9d2d39952c19f77d0cc89703b80c0a0.image_.600x600-1.jpg" alt="" width="377" height="373" class="alignnone size-large wp-image-7637" srcset="https://iotexpert.com/wp-content/uploads/2019/07/b9d2d39952c19f77d0cc89703b80c0a0.image_.600x600-1.jpg 377w, https://iotexpert.com/wp-content/uploads/2019/07/b9d2d39952c19f77d0cc89703b80c0a0.image_.600x600-1-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/b9d2d39952c19f77d0cc89703b80c0a0.image_.600x600-1-300x297.jpg 300w" sizes="auto, (max-width: 377px) 100vw, 377px" /></a></p>
<p>One thing you should be careful about is the I2C connections.  I looked around on eBay and Alibaba to find a few pictures of the I2C displays.  You should notice that all three of these displays are I2C, but all three of them have a different position and ORDER of VCC/GND/SCL/SDL  When we ordered displays from China to go onto the CY8CKIT-032 we found displays in the same BATCH that had different orders of the VCC/GND.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/muadz9bapvnzwizfk-ndhbg/" rel="attachment wp-att-7626"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/mUADz9BApvNzwiZfK-Ndhbg.jpg" alt="" width="225" height="225" class="alignnone size-full wp-image-7626" srcset="https://iotexpert.com/wp-content/uploads/2019/07/mUADz9BApvNzwiZfK-Ndhbg.jpg 225w, https://iotexpert.com/wp-content/uploads/2019/07/mUADz9BApvNzwiZfK-Ndhbg-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/mUADz9BApvNzwiZfK-Ndhbg-150x150.jpg 150w" sizes="auto, (max-width: 225px) 100vw, 225px" /></a>  <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/mjvbbenrakthvstgdwuagew/" rel="attachment wp-att-7629"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/mjVBBeNrakthvSTgdwuAGEw.jpg" alt="" width="225" height="225" class="alignnone size-large wp-image-7629" srcset="https://iotexpert.com/wp-content/uploads/2019/07/mjVBBeNrakthvSTgdwuAGEw.jpg 225w, https://iotexpert.com/wp-content/uploads/2019/07/mjVBBeNrakthvSTgdwuAGEw-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/mjVBBeNrakthvSTgdwuAGEw-150x150.jpg 150w" sizes="auto, (max-width: 225px) 100vw, 225px" /></a> <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/s-l225-2/" rel="attachment wp-att-7630"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/s-l225-2.jpg" alt="" width="225" height="225" class="alignnone size-full wp-image-7630" srcset="https://iotexpert.com/wp-content/uploads/2019/07/s-l225-2.jpg 225w, https://iotexpert.com/wp-content/uploads/2019/07/s-l225-2-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/s-l225-2-150x150.jpg 150w" sizes="auto, (max-width: 225px) 100vw, 225px" /></a></p>
<p>Here is a SPI version that has reset and data/command pin brought out.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/s-l225/" rel="attachment wp-att-7627"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/s-l225.jpg" alt="" width="225" height="225" class="alignnone size-large wp-image-7627" srcset="https://iotexpert.com/wp-content/uploads/2019/07/s-l225.jpg 225w, https://iotexpert.com/wp-content/uploads/2019/07/s-l225-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/s-l225-150x150.jpg 150w" sizes="auto, (max-width: 225px) 100vw, 225px" /></a>  <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/miivqcnyakhfayi4kzkqyuq/" rel="attachment wp-att-7628"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/miiVQcnyakhfaYI4KZKqYUQ.jpg" alt="" width="225" height="225" class="alignnone size-large wp-image-7628" srcset="https://iotexpert.com/wp-content/uploads/2019/07/miiVQcnyakhfaYI4KZKqYUQ.jpg 225w, https://iotexpert.com/wp-content/uploads/2019/07/miiVQcnyakhfaYI4KZKqYUQ-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/miiVQcnyakhfaYI4KZKqYUQ-150x150.jpg 150w" sizes="auto, (max-width: 225px) 100vw, 225px" /></a></p>
<h1>The Software Interface</h1>
<p>There are two parts to the software interface.</p>
<p>The first part is the command interface.  Inside of the chip there are a bunch of logic circuits which which configure the charge pumps, sequence COMs and SEGs, charge and discharge capacitors etc.  All of these things are configurable to allow for different configurations of screens e.g. different x-y sizes, configuration of what wires are connected to what places on the glass etc.  Before you can get the display to work correctly you must initialize all of these values by sending commands.  All the commands are 1-byte followed by 0 or more command parameters.</p>
<p>The second part is the data interface.  Inside of the SSD1306 chip there is a Graphics Display DRAM &#8211; GDDRAM which has 1 bit for every pixel on the screen. The state machine inside of the chip called the Display Controller will loop through the bits one by one and display them on the correct place on the screen.  This means that your MCU does not need to do anything to keep the display up to date.  When you want a pixel lit up on the screen you just need to write the correct location in the GDDRAM.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-07-28-at-5-04-06-pm/" rel="attachment wp-att-7676"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM-917x1024.png" alt="" width="917" height="1024" class="alignnone size-large wp-image-7676" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM-917x1024.png 917w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM-600x670.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM-269x300.png 269w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM-768x857.png 768w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.04.06-PM.png 1516w" sizes="auto, (max-width: 917px) 100vw, 917px" /></a></p>
<p>For the rest of this article I will focus on the serial interface, I2C.  How do you send commands and data?  Simple.  When you start a transaction you send a control byte which tells the controller what to expect next.  There are four legal control bytes.</p>
<ul>
<li>0b10000000 = 0x80 = multiple commands</li>
<li>0b00000000 = 0x00 = one command</li>
<li>0b11000000 = 0xC0 = multiple data</li>
<li>0b01000000 = 0x40 = one data byte</li>
</ul>
<p>Here is the picture from the datasheet (which I don&#8217;t find particularly illuminating) but it does describe the control byte.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-07-28-at-5-21-23-pm/" rel="attachment wp-att-7677"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM-1024x614.png" alt="" width="1024" height="614" class="alignnone size-large wp-image-7677" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM-1024x614.png 1024w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM-600x360.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM-300x180.png 300w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM-768x461.png 768w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-5.21.23-PM.png 1394w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>To send commands you write to the I2C bus with a control byte, then you send the command, then you send the optional parameters.  If you want to send multiple commands you send the control byte 0x80, the command + parameters as many as you need.</p>
<h1>The SSD1306 Driver Registers</h1>
<p>In order for the driver chip to drive the screen you need to configure:</p>
<ol>
<li>How the driver is electrically connected to the OLED Screen</li>
<li>What are the electrical parameters of the screen</li>
<li>What are the electrical parameters of the system</li>
<li>How you want to address the frame buffer</li>
<li>The automatic scroll configuration settings</li>
<li>The pixel data for the frame buffer, though it will happily display noise.</li>
</ol>
<p>If you bought this screen from eBay, Adafruit, Alibaba etc. then you will get no say in 1-3, the electrical parameters of the system.  Your screen will come prewired with all of the capacitors, OLED etc already attached to your driver commons and segments.  If you didn&#8217;t buy the screen prepackaged, then it is highly unlikely you are reading this article.  What this means is that you need to know the initializing sequence required to get the screen to work properly, then you just send the sequence down the wire from your MCU to the screen.  From looking around on the internet, it appears to me that there in only one parameter that is different in any of the screens that I could find.  Specifically the number of lines on the screen &#8211; either 32 or 64.  Which means that all of these initialization implementations should really on have one difference register 0xA8 should be set to either n-1 aka 31 or 63</p>
<p>The other difference that you will see between different implementations is the memory address mode.  In other words, how do you want to write data into the frame buffer from the MCU.  Many of the open source graphics libraries use &#8220;Horizontal&#8221; mode.  The Segger emWin library that I am using uses &#8220;Page&#8221; mode.  More on this later.</p>
<p>When you look in the data sheet, unfortunately they mix and match the order of the information.  However, from the data sheet, the categories are:</p>
<ol>
<li>Fundamental Commands</li>
<li>Scrolling Commands</li>
<li>Address Setting Commands</li>
<li>Hardware Configuration</li>
<li>Timing and Driving Scheme</li>
<li>Charge Pump</li>
</ol>
<p>I won&#8217;t put screen shots of the whole data sheet into this article, but I will show the command table and make a few clarifications on the text.  Or at least I will clarify places where I got confused.</p>
<p>As to the fundamental commands.  I tried a bunch of different contrast settings on my screens and could not tell the difference between them.  I tried from 0x10 to 0xFF and they all looked the same to me.  The best course of action is to use the default 0x7F.  I don&#8217;t really know why there is a command 0xA5 &#8220;Entire Display ON ignore RAM&#8221;.  The data sheet says &#8220;A5h command forces the entire display to be “ON”, regardless of the contents of the display data RAM&#8221;.  I can&#8217;t think of a single use case for this.  I suppose that if you issue 0xAE the screen will be all black&#8230; and if you issue 0xA5 the screen will be all white?  But why?</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-17-14-am/" rel="attachment wp-att-7690"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM-1024x476.png" alt="" width="1024" height="476" class="alignnone size-large wp-image-7690" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM-1024x476.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM-600x279.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM-300x139.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM-768x357.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.17.14-AM.png 1610w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And my definitions in the C driver file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">////////////////////////////////////////////////////////////////////////
// Fundamental Command Table Page 28
////////////////////////////////////////////////////////////////////////
#define OLED_SETCONTRAST                              0x81
// 0x81 + 0-0xFF Contrast ... reset = 0x7F

// A4/A5 commands to resume displaying data
// A4 = Resume to RAM content display
// A5 = Ignore RAM content (but why?)
#define OLED_DISPLAYALLONRESUME                       0xA4
#define OLED_DISPLAYALLONIGNORE                       0xA5

// 0xA6/A7 Normal 1=white 0=black Inverse 0=white  1=black
#define OLED_DISPLAYNORMAL                            0xA6
#define OLED_DISPLAYINVERT                            0xA7

// 0xAE/AF are a pair to turn screen off/on
#define OLED_DISPLAYOFF                               0xAE
#define OLED_DISPLAYON                                0xAF</pre>
<p>In the next section of the command table are the &#8220;Scrolling&#8221; commands.  It appears that this graphics chip was setup to display text that is 8-pixels high.  The scrolling commands will let you move the screen up/down and left/right to scroll automatically without having to update the the frame buffer.  In other words it can efficiently scroll the screen without a bunch of load on your MCU CPU or on the data bus between them.  The Adafruit graphics library provides the scrolling commands.  However, I am not using them with the Segger Library.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-8-41-09-am/" rel="attachment wp-att-7698"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM-1024x577.png" alt="" width="1024" height="577" class="alignnone size-large wp-image-7698" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM-1024x577.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM-600x338.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM-300x169.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM-768x433.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-8.41.09-AM.png 1692w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The next section has the commands to configure how your MCU writes data into the Graphics RAM aka the frame buffer. These commands fall into two categories.  First the address mode.  The address modes help you efficiently write the GDDRAM.  When you send data to the frame buffer you really don&#8217;t want to send</p>
<ul>
<li>address, pixel, address, pixel, &#8230;</li>
</ul>
<p>What you really would like to do is send</p>
<ul>
<li>Address, pixel, pixel, pixel &#8230; (and have the address be automatically incremented</li>
</ul>
<p>At first blush you might think&#8230; why do I need a mode?  Well there are some people who want the x address incremented&#8230; there are some people who want the y-address incremented and there are some people who want to have page address access.  And what do you do when you get to the end of a line? or a column or a page? and what does the end mean?</p>
<p>The second set of commands in this table are the commands to set the starting address before you write data.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-16-11-am/" rel="attachment wp-att-7687"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM-1024x733.png" alt="" width="1024" height="733" class="alignnone size-large wp-image-7687" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM-1024x733.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM-600x430.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM-300x215.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM-768x550.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.11-AM.png 1634w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a>  <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-16-33-am/" rel="attachment wp-att-7689"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM-1024x409.png" alt="" width="1024" height="409" class="alignnone size-large wp-image-7689" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM-1024x409.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM-600x240.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM-300x120.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM-768x307.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.16.33-AM.png 1642w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">////////////////////////////////////////////////////////////////////////
// Address Setting Command Table
////////////////////////////////////////////////////////////////////////

// 00-0F - set lower nibble of page address
// 10-1F - set upper niddle of page address

#define OLED_SETMEMORYMODE                            0x20
#define OLED_SETMEMORYMODE_HORIZONTAL                 0x00
#define OLED_SETMEMORYMODE_VERTICAL                   0x01
#define OLED_SETMEMORYMODE_PAGE                       0x02

// 0x20 + 00 = horizontal, 01 = vertical 2= page &gt;=3=illegal

// Only used for horizonal and vertical address modes
#define OLED_SETCOLUMNADDR                            0x21
// 2 byte Parameter
// 0-127 column start address 
// 0-127 column end address

#define OLED_SETPAGEADDR                              0x22
// 2 byte parameter
// 0-7 page start address
// 0-7 page end Address

// 0xB0 -0xB7 ..... Pick page 0-7</pre>
<p>The hardware configuration registers allow the LED display maker to hookup the common and segment signals in an order that makes sense for the placement of the chip on the OLED glass.  For a 128&#215;64 display there are at least 196 wires, so the routing of these wires may be a total pain in the ass depending on the location of the chip.  For instance the left and right might be swapped&#8230; or half the wires might come out on one side and the other half on the other side.  These registers allow the board designer flexibility in making these connections.  Commands 0xA0, 0xA1, 0xA8, 0xC0, 0xC8, 0xD3, 0xDa will all be fixed based on the layout.  You have no control and they need to be set correctly or something crazy will come out.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-15-41-am/" rel="attachment wp-att-7686"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM-1024x768.png" alt="" width="1024" height="768" class="alignnone size-large wp-image-7686" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM-1024x768.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM-600x450.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM-300x225.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM-768x576.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.15.41-AM.png 1662w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">////////////////////////////////////////////////////////////////////////
// Hardware Configuration
////////////////////////////////////////////////////////////////////////

// 40-7F - set address startline from 0-127 (6-bits)
#define OLED_SETSTARTLINE_ZERO                        0x40

// Y Direction
#define OLED_SEGREMAPNORMAL                           0xA0
#define OLED_SEGREMAPINV                              0xA1

#define OLED_SETMULTIPLEX                             0xA8
// 0xA8, number of rows -1 ... e.g. 0xA8, 63

// X Direction
#define OLED_COMSCANINC                               0xC0
#define OLED_COMSCANDEC                               0xC8

// double byte with image wrap ...probably should be 0
#define OLED_SETDISPLAYOFFSET                         0xD3

// Double Byte Hardware com pins configuration
#define OLED_SETCOMPINS                               0xDA
// legal values 0x02, 0x12, 0x022, 0x032
</pre>
<p>The next sections of commands are part of the electrical configuration for the glass.</p>
<p>0xD5 essentially sets up the display update rate by 1) setting the display update clock frequency and 2) setting up a divider for that clock.</p>
<p>0xDB and 0xD9 sets up a parameter that is display dependent.  That being said I tried a bunch of different values and they all look the same to me.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-13-52-am/" rel="attachment wp-att-7685"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM-1024x655.png" alt="" width="1024" height="655" class="alignnone size-large wp-image-7685" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM-1024x655.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM-600x384.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM-300x192.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM-768x491.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.13.52-AM.png 1642w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">////////////////////////////////////////////////////////////////////////
// Timing and Driving Scheme Settings
////////////////////////////////////////////////////////////////////////

#define OLED_SETDISPLAYCLOCKDIV                       0xD5
#define OLED_SETPRECHARGE                             0xD9

#define OLED_SETVCOMDESELECT                          0xDB
#define OLED_NOP                                      0xE3
</pre>
<p>These displays require a high voltage to program the liquid crystal in the display.  That voltage can either be supplied by an external pin or by an internal charge pump.  All the displays that I have seen use an internal charge pump.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-01-at-6-09-12-am/" rel="attachment wp-att-7684"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM-1024x373.png" alt="" width="1024" height="373" class="alignnone size-large wp-image-7684" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM-1024x373.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM-600x218.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM-300x109.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM-768x280.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-01-at-6.09.12-AM.png 1478w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">////////////////////////////////////////////////////////////////////////
// Charge Pump Regulator
////////////////////////////////////////////////////////////////////////

#define OLED_CHARGEPUMP                               0x8D
#define OLED_CHARGEPUMP_ON                            0x14
#define OLED_CHARGEPUMP_OFF                           0x10
</pre>
<h1>The SSD1306 Graphics Data RAM</h1>
<p>In order to actually get data to display on the screen you need to write 1&#8217;s and 0&#8217;s into the Graphics Data RAM that represents your image.  The memory is actually organized into 8 pages that are each 128 bits wide and 8 bits tall.  This means that if you write 0b10101010 to location (0,0) you will get the first 8 pixels in a column on the screen to be on,off,on,off,on,off,on,off.  Notice that I said vertical column and not row.  Here is a picture from the data sheet.  That shows the pages:</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-9-33-51-am/" rel="attachment wp-att-7709"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM-1024x614.png" alt="" width="1024" height="614" class="alignnone size-large wp-image-7709" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM-1024x614.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM-600x360.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM-300x180.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM-768x461.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.33.51-AM.png 1604w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And then they show you in the data sheet that the pixels go down from the first row of the page.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-9-50-34-am/" rel="attachment wp-att-7712"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM-1024x303.png" alt="" width="1024" height="303" class="alignnone size-large wp-image-7712" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM-1024x303.png 1024w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM-600x177.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM-300x89.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM-768x227.png 768w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.50.34-AM.png 1542w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>In order to make the writing process easier and lower bandwidth the SSD1306 has three automatic addressing modes.</p>
<ul>
<li>Horizontal &#8211; Set the page address start, end and the column start and end&#8230; bytes write 8 vertical pixels on the page. Each byte write advances the column until it wraps to the next page and resets the column to the &#8220;start&#8221;</li>
<li>Vertical &#8211; Set the page address start, end and the column start and end&#8230; bytes write 8 vertical pixels on the page.  Each byte write advances the page until it wraps vertically where it increments the column and resets the page back to the start page.</li>
<li>Page &#8211; Set the page address and column start/end.  Each byte writes vertically.  Wraps back onto the same page when it hits the end column.</li>
</ul>
<p>In Horizontal and Vertical mode you</p>
<ul>
<li>Set the range of columns that you want to write (using 0x22)</li>
<li>Set the range of pages you want to write (using 0x21)</li>
<li>Write bytes</li>
</ul>
<p>In the page mode you</p>
<ul>
<li>Set the page (remember you can only write one page at a time in page mode) using 0xB0-0xB7</li>
<li>Set the start column using 0x0? and 0x1?</li>
</ul>
<p>Here is a picture from the data sheet of horizontal address mode:</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-9-41-58-am/" rel="attachment wp-att-7710"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.41.58-AM.png" alt="" width="976" height="334" class="alignnone size-full wp-image-7710" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.41.58-AM.png 976w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.41.58-AM-600x205.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.41.58-AM-300x103.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.41.58-AM-768x263.png 768w" sizes="auto, (max-width: 976px) 100vw, 976px" /></a></p>
<p>In this bit of example code I am saying to iterate through the pages 0-&gt;7&#8230; in other words all of the pages.  And to start in column 0.  This example will make 12 columns of pixels each 8 high starting a (0,0) on the screen&#8230;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">    char horizontalExample[]= {
            0xAE,
            0x20, /// address mode
            0x00, // Horizontal
            0xA4,
            0xAF,
            0x22, //Set page address range
            0,
            7,
            0x21, // column start and end address
            0,
            127,
    };

    I2C_WriteCmdStream(horizontalExample, sizeof(horizontalExample));
    // Write twelve bytes onto screen with 0b10101010
    for(int i=0;i&lt;12;i++)
        I2C_WriteData(0xAA);</pre>
<p>Here is a picture of what it does.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0774-2/" rel="attachment wp-att-7719"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2-1024x1005.jpg" alt="" width="1024" height="1005" class="alignnone size-large wp-image-7719" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2-1024x1005.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2-600x589.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2-300x294.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2-768x754.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0774-2.jpg 1075w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Here is a picture from the data sheet of vertical address mode:</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-9-42-06-am/" rel="attachment wp-att-7711"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.42.06-AM.png" alt="" width="952" height="352" class="alignnone size-large wp-image-7711" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.42.06-AM.png 952w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.42.06-AM-600x222.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.42.06-AM-300x111.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-9.42.06-AM-768x284.png 768w" sizes="auto, (max-width: 952px) 100vw, 952px" /></a></p>
<p>This example code sets the page range to 0&#8211;&gt;7  (the whole screen) and the column range 0&#8211;&gt;127 (the whole screen).  Then writes 12 bytes.  You can see it wrap at the bottom and move back to page 0 column 1.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">    char verticalExample[]= {
            0xAE,
            0x20, /// address mode
            0x01, //  vertical
            0xA4,
            0xAF,
            0x22, //Set page address range
            0,
            7,
            0x21, // column start and end address
            0,
            127,
    };

    I2C_WriteCmdStream(verticalExample, sizeof(verticalExample));
    // Write twelve bytes onto screen with 0b10101010
    for(int i=0;i&lt;12;i++)
        I2C_WriteData(0xAA); 
</pre>
<p>&nbsp;</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0773/" rel="attachment wp-att-7717"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773-1024x943.jpg" alt="" width="1024" height="943" class="alignnone size-large wp-image-7717" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773-1024x943.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773-600x552.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773-300x276.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773-768x707.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0773.jpg 1058w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>&nbsp;</p>
<p>In page mode you just set the page and the start and end column.  0xB0 means page 0, 0xB1 means page 1&#8230; 0xB7 means page 7.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-08-03-at-11-01-46-am/" rel="attachment wp-att-7716"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-11.01.46-AM.png" alt="" width="932" height="304" class="alignnone size-full wp-image-7716" srcset="https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-11.01.46-AM.png 932w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-11.01.46-AM-600x196.png 600w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-11.01.46-AM-300x98.png 300w, https://iotexpert.com/wp-content/uploads/2019/08/Screen-Shot-2019-08-03-at-11.01.46-AM-768x251.png 768w" sizes="auto, (max-width: 932px) 100vw, 932px" /></a></p>
<p>You can see that I started from column 0x78 (meaning column 120) and that it wraps back to column 0 on the SAME page.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">    char pageExample[]= {
            0xAE,
            0x20, // address mode
            0x02, // Page mode
            0xA4, // Resume from ram
            0xAF, // Screen on
            0xB0, // Start from page 0
            // Start from column 0x78 aka 120
            0x08, // Column lower nibble address
            0x17  // Column upper nibble address
    };

    I2C_WriteCmdStream(pageExample, sizeof(pageExample));

    // Write twelve bytes onto screen with 0b10101010
    for(int i=0;i&lt;12;i++)
        I2C_WriteData(0xAA);</pre>
<p>Here is what it looks like.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0772/" rel="attachment wp-att-7714"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-1024x1009.jpg" alt="" width="1024" height="1009" class="alignnone size-large wp-image-7714" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-1024x1009.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-600x591.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-300x296.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772-768x757.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0772.jpg 1155w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Reading from the Frame Buffer</h1>
<p>Now that you know how to write to the Frame Buffer, the next question is how do you read?  For instance if you want to turn on 1 pixel (of a byte) but leave the others alone can you do this? The answer is NO.  In serial mode the device only writes.  In all of the Graphics libraries that I have seen they handle this by having a Frame Buffer in the MCU as well.  Duplicated resources&#8230; oh well.</p>
<h1>My Initialization Sequence</h1>
<p>I have a function that writes an array of bytes to the command registers.  So for me to initialize the screen I just need to set up that array.  Here is my best known setup.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">    const char initializeCmds[]={
        //////// Fundamental Commands
        OLED_DISPLAYOFF,          // 0xAE Screen Off
        OLED_SETCONTRAST,         // 0x81 Set contrast control
        0x7F,                     // 0-FF ... default half way

        OLED_DISPLAYNORMAL,       // 0xA6, //Set normal display 

        //////// Scrolling Commands
        OLED_DEACTIVATE_SCROLL,   // Deactive scroll

        //////// Addressing Commands
        OLED_SETMEMORYMODE,       // 0x20, //Set memory address mode
        OLED_SETMEMORYMODE_PAGE,  // Page

        //////// Hardware Configuration Commands
        OLED_SEGREMAPINV,         // 0xA1, //Set segment re-map 
        OLED_SETMULTIPLEX,        // 0xA8 Set multiplex ratio
        0x3F,                     // Vertical Size - 1
        OLED_COMSCANDEC,          // 0xC0 Set COM output scan direction
        OLED_SETDISPLAYOFFSET,    // 0xD3 Set Display Offset
        0x00,                     //
        OLED_SETCOMPINS,          // 0xDA Set COM pins hardware configuration
        0x12,                     // Alternate com config &amp; disable com left/right
   
        //////// Timing and Driving Settings
        OLED_SETDISPLAYCLOCKDIV,  // 0xD5 Set display oscillator frequency 0-0xF /clock divide ratio 0-0xF
        0x80,                     // Default value
        OLED_SETPRECHARGE,        // 0xD9 Set pre-changed period
        0x22,                     // Default 0x22
        OLED_SETVCOMDESELECT,     // 0xDB, //Set VCOMH Deselected level
        0x20,                     // Default 

        //////// Charge pump regulator
        OLED_CHARGEPUMP,          // 0x8D Set charge pump
        OLED_CHARGEPUMP_ON,       // 0x14 VCC generated by internal DC/DC circuit

        // Turn the screen back on...       
        OLED_DISPLAYALLONRESUME,  // 0xA4, //Set entire display on/off
        OLED_DISPLAYON,           // 0xAF  //Set display on
    };
</pre>
<h1>Some Other Initialization Sequences</h1>
<p>If you look around you will find many different SSD1306 libraries.  You can run <a href="https://github.com/search?q=ssd1306" target="_blank" rel="noopener noreferrer">this</a> search on github.</p>
<p>Here is one example from https://github.com/vadzimyatskevich/SSD1306/blob/master/src/ssd1306.c  This is pretty much the same as mine except that the author put them in some other order than the data sheet.  I am not a huge fan of &#8220;ssd1306Command( SSD1306_SEGREMAP | 0x1)&#8221; but it does work.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">void  ssd1306Init(uint8_t vccstate)
{
  _font = (FONT_INFO*)&amp;ubuntuMono_24ptFontInfo;
  
    // Initialisation sequence
    ssd1306TurnOff();
    //  1. set mux ratio
    ssd1306Command(   SSD1306_SETMULTIPLEX );
    ssd1306Command(   0x3F );
    //  2. set display offset
    ssd1306Command(   SSD1306_SETDISPLAYOFFSET );
    ssd1306Command(   0x0 );
    //  3. set display start line
    ssd1306Command(   SSD1306_SETSTARTLINE | 0x0 ); 
    ssd1306Command( SSD1306_MEMORYMODE);                    // 0x20
    ssd1306Command( 0x00);                                  // 0x0 act like ks0108
    //  4. set Segment re-map A0h/A1h    
    ssd1306Command(   SSD1306_SEGREMAP | 0x1);
    //   5. Set COM Output Scan Direction C0h/C8h
    ssd1306Command(   SSD1306_COMSCANDEC);
    //  6. Set COM Pins hardware configuration DAh, 12
    ssd1306Command(   SSD1306_SETCOMPINS);
    ssd1306Command(   0x12);
    //  7. Set Contrast Control 81h, 7Fh
    ssd1306Command(   SSD1306_SETCONTRAST );
    if (vccstate == SSD1306_EXTERNALVCC) { 
        ssd1306Command(   0x9F );
    } else { 
        ssd1306Command(   0xff );
    }
    //  8. Disable Entire Display On A4h
    ssd1306Command(   SSD1306_DISPLAYALLON_RESUME);
    //  9. Set Normal Display A6h 
    ssd1306Command(   SSD1306_NORMALDISPLAY);
    //  10. Set Osc Frequency  D5h, 80h 
    ssd1306Command(   SSD1306_SETDISPLAYCLOCKDIV);
    ssd1306Command(   0x80);
    //  11. Enable charge pump regulator 8Dh, 14h 
    ssd1306Command(   SSD1306_CHARGEPUMP );
    if (vccstate == SSD1306_EXTERNALVCC) { 
        ssd1306Command(   0x10);
    } else { 
        ssd1306Command(   0x14);
    }
    //  12. Display On AFh 
    ssd1306TurnOn();

}</pre>
<p>Here is another example from git@github.com:lexus2k/ssd1306.git</p>
<p>https://github.com/lexus2k/ssd1306/blob/master/src/lcd/oled_ssd1306.c</p>
<p>Honestly if I had found this originally I would not have gone to all the trouble.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">static const uint8_t PROGMEM s_oled128x64_initData[] =
{
#ifdef SDL_EMULATION
    SDL_LCD_SSD1306,
    0x00,
#endif
    SSD1306_DISPLAYOFF, // display off
    SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE, // Page Addressing mode
    SSD1306_COMSCANDEC,             // Scan from 127 to 0 (Reverse scan)
    SSD1306_SETSTARTLINE | 0x00,    // First line to start scanning from
    SSD1306_SETCONTRAST, 0x7F,      // contast value to 0x7F according to datasheet
    SSD1306_SEGREMAP | 0x01,        // Use reverse mapping. 0x00 - is normal mapping
    SSD1306_NORMALDISPLAY,
    SSD1306_SETMULTIPLEX, 63,       // Reset to default MUX. See datasheet
    SSD1306_SETDISPLAYOFFSET, 0x00, // no offset
    SSD1306_SETDISPLAYCLOCKDIV, 0x80,// set to default ratio/osc frequency
    SSD1306_SETPRECHARGE, 0x22,     // switch precharge to 0x22 // 0xF1
    SSD1306_SETCOMPINS, 0x12,       // set divide ratio
    SSD1306_SETVCOMDETECT, 0x20,    // vcom deselect to 0x20 // 0x40
    SSD1306_CHARGEPUMP, 0x14,       // Enable charge pump
    SSD1306_DISPLAYALLON_RESUME,
    SSD1306_DISPLAYON,
};</pre>
<h1>Debug: Test the Hardware</h1>
<p>If a your screen is not working, the first thing to do is use a multimeter and make sure that VCC=SCL=SDA=3.3V.  (in the picture below my camera caught the screen refresh partially through&#8230; It looks fine at normal speed).  I have the red probe attached to the SCL.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0759/" rel="attachment wp-att-7641"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0759-1024x870.jpg" alt="" width="1024" height="870" class="alignnone size-large wp-image-7641" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0759-1024x870.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0759-600x510.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0759-300x255.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0759-768x653.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>I would then run the <a href="https://iotexpert.com/?s=bridge+control" target="_blank" rel="noopener noreferrer">bridge control panel</a> and make sure that the device is responding.  You can do this by pressing &#8220;List&#8221;.  In the picture below you can see that there are two devices attached to the bus,  my screen is set to 0x78/0x3C.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-07-28-at-8-51-00-am/" rel="attachment wp-att-7640"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM-1024x818.png" alt="" width="1024" height="818" class="alignnone size-large wp-image-7640" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM-1024x818.png 1024w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM-600x480.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM-300x240.png 300w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM-768x614.png 768w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-8.51.00-AM.png 1674w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>If you don&#8217;t have the bridge control panel then you can implement I2Cdetect using your development kit.   Read about it <a href="https://iotexpert.com/2019/08/05/i2c-detect-with-psoc-6/" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p><a href="https://iotexpert.com/2019/08/05/i2c-detect-with-psoc-6/screen-shot-2019-07-28-at-10-50-21-am/" rel="attachment wp-att-7658"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM-1024x852.png" alt="" width="1024" height="852" class="alignnone size-large wp-image-7658" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM-1024x852.png 1024w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM-600x499.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM-300x250.png 300w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM-768x639.png 768w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-10.50.21-AM.png 1214w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The next thing to do is attach a logic analyzer and make sure that the startup commands are coming out of your MCU correctly.  Notice that the 00, 0xAE, 0x81&#8230; are exactly the configuration sequence that I wrote in the driver code above.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/screen-shot-2019-07-28-at-11-46-45-am/" rel="attachment wp-att-7674"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-11.46.45-AM-1024x558.png" alt="" width="1024" height="558" class="alignnone size-large wp-image-7674" srcset="https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-11.46.45-AM-1024x558.png 1024w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-11.46.45-AM-600x327.png 600w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-11.46.45-AM-300x163.png 300w, https://iotexpert.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-28-at-11.46.45-AM-768x418.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Debug: Test the Firmware</h1>
<p>If your screen is still not working here are some problems and what to do about them.</p>
<ul>
<li><strong>Speckled Screen</strong></li>
<li><strong>Solid Screen</strong></li>
<li><strong>Screen Flipped in the Y direction</strong></li>
<li><strong>Screen Flipped in the X Direction</strong></li>
<li><strong>Screen Flipped in both Directions</strong></li>
<li><strong>Screen is Inverted</strong></li>
<li><strong>Image is Partially off the Screen</strong></li>
<li><strong>Image is Wrapped on the Screen</strong></li>
<li><strong>Black Screen</strong></li>
<li><strong>Screen Has Gone Crazy</strong></li>
</ul>
<p><span style="text-decoration: underline;"><strong>Speckled Screen</strong></span></p>
<p>If you have the speckled screen this means that your screen is displaying an uninitialized frame buffer which the SSD people call the GDDRAM.  These are basically the random 0 and 1s that are the startup values in the SSD1306.  If this is happening then your graphic data is probably not being transferred between your MCU and the SSD1306.  This almost certainly means you have a problem in your porting layer.</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0743/" rel="attachment wp-att-7594"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0743-1024x931.jpg" alt="" width="1024" height="931" class="alignnone size-large wp-image-7594" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0743-1024x931.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0743-600x545.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0743-300x273.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0743-768x698.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<div>
<div>
<p><span style="text-decoration: underline;"><strong>Speckled Screen</strong></span></p>
<p>If your screen is solid white that probably means you turned the screen back on without resuming from the graphics ram.  You did this:</p>
</div>
</div>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">OLED_DISPLAYALLONIGNORE,  // 0xA5, //Set entire display on/off</pre>
<p>instead of this:</p>
<div>
<div>
<pre class="EnlighterJSRAW" data-enlighter-language="c">OLED_DISPLAYALLONRESUME,  // 0xA4, //Set entire display on/off</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0771/" rel="attachment wp-att-7702"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771-1024x824.jpg" alt="" width="1024" height="824" class="alignnone size-large wp-image-7702" srcset="https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771-1024x824.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771-600x483.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771-300x241.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771-768x618.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/08/IMG_0771.jpg 1556w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><span style="text-decoration: underline;"><strong>Screen Flipped in the Y direction</strong></span></p>
</div>
<div>The commands C0/C8 set the direction in which the com lines are scanned.  Either from top to bottom or bottom to top.  Change C0&#8211;&gt;C8 to the other way.</div>
<div>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#define OLED_COMSCANINC                               0xC0
#define OLED_COMSCANDEC                               0xC8</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0746/" rel="attachment wp-att-7607"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746-1024x924.jpg" alt="" width="1024" height="924" class="alignnone size-large wp-image-7607" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746-1024x924.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746-600x542.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746-300x271.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746-768x693.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0746.jpg 1667w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
</div>
</div>
<p><span style="text-decoration: underline;"><strong>Screen Flipped in the X Direction</strong></span></p>
<p>In the X-Direction the A0/A1 set the configuration of scanning.  Try using A0&#8211;&gt;A8 or the other way.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">// X Direction Scanning 
#define OLED_SEGREMAPNORMAL                           0xA0
#define OLED_SEGREMAPINV                              0xA1</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0745/" rel="attachment wp-att-7608"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745-1024x781.jpg" alt="" width="1024" height="781" class="alignnone size-large wp-image-7608" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745-1024x781.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745-600x458.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745-300x229.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745-768x586.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0745.jpg 1597w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><span style="text-decoration: underline;"><strong>Screen Flipped in both Directions</strong></span></p>
<p>If it is flipped in both X and Y direction then flip both of the direction registers.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">// Y Direction
#define OLED_SEGREMAPNORMAL                           0xA0
#define OLED_SEGREMAPINV                              0xA1

// X Direction
#define OLED_COMSCANINC                               0xC0
#define OLED_COMSCANDEC                               0xC8</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0748/" rel="attachment wp-att-7610"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748-947x1024.jpg" alt="" width="947" height="1024" class="alignnone size-large wp-image-7610" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748-947x1024.jpg 947w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748-600x649.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748-277x300.jpg 277w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748-768x831.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0748.jpg 1249w" sizes="auto, (max-width: 947px) 100vw, 947px" /></a></p>
<p><span style="text-decoration: underline;"><strong>Screen is Inverted</strong></span></p>
<p>If your screen is inverted then try A8&#8211;&gt;A6</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">#define OLED_DISPLAYNORMAL                            0xA6
#define OLED_DISPLAYINVERT                            0xA7</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0749/" rel="attachment wp-att-7611"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749-1024x972.jpg" alt="" width="1024" height="972" class="alignnone size-large wp-image-7611" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749-1024x972.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749-600x570.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749-300x285.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749-768x729.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0749.jpg 1370w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><span style="text-decoration: underline;"><strong>Image is Partially off the Screen</strong></span></p>
<p>If your image is off the screen the you probably have the wrong value for MULTIPLEX.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">#define OLED_SETMULTIPLEX                             0xA8</pre>
<p>The parameter is supposed to be the number of lines on the screen -1.  In my case the screen is 128&#215;64 so my valued should be 63 aka 0x3F</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">        OLED_SETMULTIPLEX,        // 0xA8 Set multiplex ratio
        0x3F,                     // Vertical Size - 1</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0750/" rel="attachment wp-att-7613"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750-1024x984.jpg" alt="" width="1024" height="984" class="alignnone size-large wp-image-7613" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750-1024x984.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750-600x577.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750-300x288.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750-768x738.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0750.jpg 1389w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><span style="text-decoration: underline;"><strong>Image is Wrapped on the Screen</strong></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">// Double byte CMD image wrap ...probably should be 0
#define OLED_SETDISPLAYOFFSET                         0xD3</pre>
<p>The offset value allows the board designer to hook up the rows in a crazy fashion.   My screen has the top row to the top row number.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">        OLED_SETDISPLAYOFFSET,    // 0xD3 Set Display Offset
        0x00,                     //
</pre>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0751/" rel="attachment wp-att-7614"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-1024x1012.jpg" alt="" width="1024" height="1012" class="alignnone size-large wp-image-7614" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-1024x1012.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-600x593.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-300x296.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751-768x759.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0751.jpg 1351w" sizes="auto, (max-width: 1024px) 100vw, 1024px" />\</a></p>
<p><span style="text-decoration: underline;"><strong>Black Screen</strong></span></p>
<p>If you screen is totally dead&#8230;</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0752/" rel="attachment wp-att-7615"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752-953x1024.jpg" alt="" width="953" height="1024" class="alignnone size-large wp-image-7615" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752-953x1024.jpg 953w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752-600x644.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752-279x300.jpg 279w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752-768x825.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0752.jpg 1352w" sizes="auto, (max-width: 953px) 100vw, 953px" /></a></p>
<p>Then the charge pump may be off</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">        //////// Charge pump regulator
        OLED_CHARGEPUMP,          // 0x8D Set charge pump
        0x14,                     // VCC generated by internal DC/DC circuit
</pre>
<p>or maybe the screen is off&#8230; try turning it on.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">        OLED_DISPLAYON,           // 0xAF  //Set display on</pre>
<p>or maybe you haven&#8217;t displayed anything. The screen is off trying sending a screen invert</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#define OLED_DISPLAYINVERT                            0xA7
</pre>
<p><span style="text-decoration: underline;"><strong>The Screen Has Gone Crazy</strong></span></p>
<p>The register 0xDA SetComPins register will make some crazy results of it isn&#8217;t set correctly.  For my 0.96&#8243; inch screen it needs to be set to 0x12</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">// Double Byte Hardware com pins configuration
#define OLED_SETCOMPINS                               0xDA
// legal values 0x02, 0x12, 0x022, 0x032</pre>
<p>This is what happens with 0x02 [If you see the note below from Ivan, 0x02 is apparently for 128&#215;32 and this screen is 128&#215;64=0x12]</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0755/" rel="attachment wp-att-7617"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-1024x1016.jpg" alt="" width="1024" height="1016" class="alignnone size-large wp-image-7617" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-1024x1016.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-600x595.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-150x150.jpg 150w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-300x298.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755-768x762.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0755.jpg 1369w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a> <a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0757/" rel="attachment wp-att-7618"></a></p>
<p>And 0x22</p>
<p><a href="https://iotexpert.com/?attachment_id=7619" rel="attachment wp-att-7619"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756-999x1024.jpg" alt="" width="999" height="1024" class="alignnone size-large wp-image-7619" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756-999x1024.jpg 999w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756-600x615.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756-293x300.jpg 293w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756-768x787.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0756.jpg 1345w" sizes="auto, (max-width: 999px) 100vw, 999px" /></a></p>
<p>Finally 0x32</p>
<p><a href="https://iotexpert.com/2019/08/07/debugging-ssd1306-display-problems/img_0757/" rel="attachment wp-att-7618"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-1024x1024.jpg" alt="" width="1024" height="1024" class="alignnone size-large wp-image-7618" srcset="https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-1024x1024.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-300x300.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-600x600.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-150x150.jpg 150w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757-768x768.jpg 768w, https://iotexpert.com/wp-content/uploads/2019/07/IMG_0757.jpg 1238w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>This was absolutely the craziest rabbit hole that I have ventured down. Nicholas has talked to me 10 times about doing this and he thinks I’m crazy.  Oh well.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/debugging-ssd1306-display-problems/feed/</wfw:commentRss>
			<slash:comments>53</slash:comments>
		
		
			</item>
		<item>
		<title>IoT Expert Logo -&gt; EPD &#8211; Bitmap Madness (Part 2)</title>
		<link>https://iotexpert.com/iot-expert-logo-epd-bitmap-madness-part-2/</link>
					<comments>https://iotexpert.com/iot-expert-logo-epd-bitmap-madness-part-2/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 20 May 2019 12:00:31 +0000</pubDate>
				<category><![CDATA[CY8CKIT-028-EPD]]></category>
		<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6895</guid>

					<description><![CDATA[Summary In the last article I showed you how to display a bitmap in the Segger format.  In this article I will show you how to convert a BMP to a &#8220;C&#8221; file and then display it using the Segger GUI_BMP_Draw() API. To this I will follow these steps: Use GIMP to Export a Black [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>In the <a href="https://iotexpert.com/2019/05/13/iot-expert-logo-conversion-bitmap-madness-part-1/" target="_blank" rel="noopener noreferrer">last article</a> I showed you how to display a bitmap in the Segger format.  In this article I will show you how to convert a <a href="https://en.wikipedia.org/wiki/BMP_file_format" target="_blank" rel="noopener noreferrer">BMP</a> to a &#8220;C&#8221; file and then display it using the Segger GUI_BMP_Draw() API.</p>
<p>To this I will follow these steps:</p>
<ul>
<li>Use GIMP to Export a Black and White Logo</li>
<li>Convert the BMP to a &#8220;C&#8221; array using Bin2C</li>
<li>Add the C to the project and fix up the project</li>
</ul>
<h1>Use GIMP to Export a Black and White Logo as BMP</h1>
<p>As in the last article, Ill use GIMP to manipulate the IoT Expert.  First, Ill load the logo from the PNG file.</p>
<p><a href="https://iotexpert.com/?attachment_id=6908" rel="attachment wp-att-6908"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.04-PM-1024x672.png" alt="" width="1024" height="672" class="alignnone size-large wp-image-6908" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.04-PM-1024x672.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.04-PM-600x394.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.04-PM-300x197.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.04-PM-768x504.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Then I will convert the PNG to a black and white only image.  This will be a 1-bit per pixel indexed image.  Indexed means that instead of ARGB (aka 32 bits for each pixel), that the color of each pixel will be referenced via an index into a color table.  For instance the color table might look like this:</p>
<div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Index</th>
<th >Value</th>
<th >Color</th>
</tr>
</thead>
<tbody>
<tr><td >0</td>
<td >0xFF000000</td>
<td >Black</td>
</tr>

<tr><td >1</td>
<td >0xFFFFFFFF</td>
<td >White</td>
</tr>
</tbody></table></div>
<p>The BMP file will then have a color table (like the one above) and each pixel value will be an index into the table.  It turns out that these color tables must have  2^n rows where n is the number of bits in the index.  Also with the BMP format any bitmaps with 24 bits per pixel will not have a color table.</p>
<p>Gimp can convert an image to indexed.  To do this, click  Image&#8211;&gt;Mode&#8211;&gt;Indexed&#8230;</p>
<p><a href="https://iotexpert.com/?attachment_id=6907" rel="attachment wp-att-6907"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.23-PM.png" alt="" width="656" height="912" class="alignnone size-large wp-image-6907" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.23-PM.png 656w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.23-PM-600x834.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.23-PM-216x300.png 216w" sizes="auto, (max-width: 656px) 100vw, 656px" /></a></p>
<p>On this screen you will be given the option to specify the color indexes.  Notice that there is a &#8220;black and white only&#8221; option.</p>
<p><a href="https://iotexpert.com/?attachment_id=6906" rel="attachment wp-att-6906"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.40-PM.png" alt="" width="746" height="798" class="alignnone size-large wp-image-6906" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.40-PM.png 746w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.40-PM-600x642.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.40-PM-280x300.png 280w" sizes="auto, (max-width: 746px) 100vw, 746px" /></a></p>
<p>Once you have made the conversion you can see that image is now indexed.</p>
<p><a href="https://iotexpert.com/?attachment_id=6905" rel="attachment wp-att-6905"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM-1024x38.png" alt="" width="1024" height="38" class="alignnone size-large wp-image-6905" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM-1024x38.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM-600x22.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM-300x11.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM-768x28.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.31.55-PM.png 1624w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>On that screen you could have converted the image to indexed with up to 256 colors (but I choose 2 by using the Use black and white (1-bit) palette.</p>
<p><a href="https://iotexpert.com/?attachment_id=6935" rel="attachment wp-att-6935"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.25.34-AM.png" alt="" width="736" height="790" class="alignnone size-full wp-image-6935" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.25.34-AM.png 736w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.25.34-AM-600x644.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.25.34-AM-279x300.png 279w" sizes="auto, (max-width: 736px) 100vw, 736px" /></a></p>
<p>The next step is to export to a BMP using &#8220;File&#8211;&gt;Export As&#8230;&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6912" rel="attachment wp-att-6912"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.04-PM.png" alt="" width="696" height="854" class="alignnone size-large wp-image-6912" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.04-PM.png 696w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.04-PM-600x736.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.04-PM-244x300.png 244w" sizes="auto, (max-width: 696px) 100vw, 696px" /></a></p>
<p>I set the file name to &#8220;IOTexpert_Logo_Vertical_BW.bmp&#8221;.  Gimp does its magic by using the file extension.  In this case &#8220;bmp&#8221; creates a Microsoft BMP file.</p>
<p><a href="https://iotexpert.com/?attachment_id=6911" rel="attachment wp-att-6911"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM-1024x709.png" alt="" width="1024" height="709" class="alignnone size-large wp-image-6911" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM-1024x709.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM-600x415.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM-300x208.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM-768x532.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.22-PM.png 1430w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>When I hit export I get this dialog box (which I had no idea what it meant when I started). For now click &#8220;OK&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6910" rel="attachment wp-att-6910"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.37-PM.png" alt="" width="556" height="352" class="alignnone size-large wp-image-6910" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.37-PM.png 556w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.37-PM-300x190.png 300w" sizes="auto, (max-width: 556px) 100vw, 556px" /></a></p>
<p>Once the file is exported this is what I get.  OK&#8230; is not very helpful.  What happened?</p>
<p><a href="https://iotexpert.com/?attachment_id=6909" rel="attachment wp-att-6909"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.54-PM-1024x723.png" alt="" width="1024" height="723" class="alignnone size-large wp-image-6909" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.54-PM-1024x723.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.54-PM-600x424.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.54-PM-300x212.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.34.54-PM-768x543.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The answer is that an Indexed BMP does not support Alpha.  So, GIMP ditched the Alpha, which turned everything that wasnt black to the background color, which is black. So, what is the deal with the Alpha channel?  Alpha is how transparent everything is.  You can get rid of it using Layer&#8211;&gt;Transparency&#8211;&gt;Remove Alpha Channel</p>
<p><a href="https://iotexpert.com/?attachment_id=6913" rel="attachment wp-att-6913"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.37.12-PM.png" alt="" width="798" height="760" class="alignnone size-full wp-image-6913" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.37.12-PM.png 798w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.37.12-PM-600x571.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.37.12-PM-300x286.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.37.12-PM-768x731.png 768w" sizes="auto, (max-width: 798px) 100vw, 798px" /></a></p>
<p>Which once again turns my image black.  But why?  On the left hand side of the screen you will see the foreground/background colors.  And you will notice that the background is black.</p>
<p><a href="https://iotexpert.com/?attachment_id=6915" rel="attachment wp-att-6915"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM-1024x679.png" alt="" width="1024" height="679" class="alignnone size-large wp-image-6915" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM-1024x679.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM-600x398.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM-300x199.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM-768x509.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.53.58-PM.png 1928w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>To fix the problem undo the remove alpha.  Then click the little back and forth arrow to turn the background white.  Then re-remove the alpha.  Now that problem is fixed.</p>
<p><a href="https://iotexpert.com/?attachment_id=6914" rel="attachment wp-att-6914"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM-1024x681.png" alt="" width="1024" height="681" class="alignnone size-large wp-image-6914" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM-1024x681.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM-600x399.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM-300x199.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM-768x510.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.55.14-PM.png 1926w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now, I can shrink it to the right size using Image&#8211;&gt;Scale Image&#8230;</p>
<p><a href="https://iotexpert.com/?attachment_id=6918" rel="attachment wp-att-6918"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.57.57-PM.png" alt="" width="438" height="906" class="alignnone size-large wp-image-6918" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.57.57-PM.png 438w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.57.57-PM-145x300.png 145w" sizes="auto, (max-width: 438px) 100vw, 438px" /></a></p>
<p>Then pick the 276 width (aka the same width as the EPD screen)</p>
<p><a href="https://iotexpert.com/?attachment_id=6917" rel="attachment wp-att-6917"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.58.11-PM.png" alt="" width="756" height="600" class="alignnone size-large wp-image-6917" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.58.11-PM.png 756w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.58.11-PM-600x476.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.58.11-PM-300x238.png 300w" sizes="auto, (max-width: 756px) 100vw, 756px" /></a></p>
<p>Now do &#8220;File&#8211;&gt;Export As..&#8221; with a &#8220;.bmp&#8221; file name extension.  This time it doesn&#8217;t ask me about the transparency.</p>
<p><a href="https://iotexpert.com/?attachment_id=6916" rel="attachment wp-att-6916"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM-1024x703.png" alt="" width="1024" height="703" class="alignnone size-large wp-image-6916" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM-1024x703.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM-600x412.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM-300x206.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM-768x527.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-12.59.15-PM.png 1430w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And, now I have a nice BMP file.  Here is the view from the preview in Mac.</p>
<p><a href="https://iotexpert.com/?attachment_id=6919" rel="attachment wp-att-6919"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM-1024x510.png" alt="" width="1024" height="510" class="alignnone size-large wp-image-6919" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM-1024x510.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM-600x299.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM-300x149.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM-768x383.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.02.39-PM.png 1100w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>So, how do I get a BMP file into my program?  Well, I need turn it into an array of bytes.  And to do that&#8230;</p>
<h1>Segger Bin2C</h1>
<p>One of the utility programs that Segger provides is called &#8220;<a href="https://www.segger.com/free-utilities/bin2c/" target="_blank" rel="noopener noreferrer">Bin2C</a>&#8221; which can read in a file and turn it into an array of bytes in &#8220;c&#8221; format.  You can download it <a href="https://www.segger.com/downloads/free-utilities/" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p><a href="https://iotexpert.com/?attachment_id=6923" rel="attachment wp-att-6923"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-4.47.56-PM-1024x696.png" alt="" width="1024" height="696" class="alignnone size-large wp-image-6923" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-4.47.56-PM-1024x696.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-4.47.56-PM-600x408.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-4.47.56-PM-300x204.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-4.47.56-PM-768x522.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>When I run it, first I select the file, then press &#8220;Convert&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6921" rel="attachment wp-att-6921"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.04.32-PM.png" alt="" width="698" height="266" class="alignnone size-large wp-image-6921" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.04.32-PM.png 698w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.04.32-PM-600x229.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.04.32-PM-300x114.png 300w" sizes="auto, (max-width: 698px) 100vw, 698px" /></a></p>
<p>And it generates a nice array of bytes.</p>
<p><a href="https://iotexpert.com/?attachment_id=6920" rel="attachment wp-att-6920"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.05.15-PM-1024x696.png" alt="" width="1024" height="696" class="alignnone size-large wp-image-6920" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.05.15-PM-1024x696.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.05.15-PM-600x408.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.05.15-PM-300x204.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-1.05.15-PM-768x522.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Update the Project</h1>
<p>To use the array, first copy the file into your project.  You notice that the array is defined as &#8220;static&#8221; which means that it is not accessible from other files.  Remove that.  Now edit the eInkTask.c and</p>
<ol>
<li>Add an extern reference to the array of bytes</li>
<li>Make a call to &#8220;GMP_BMP_Draw()&#8221; to display the logo</li>
</ol>
<pre class="EnlighterJSRAW" data-enlighter-language="c">extern unsigned char _acIOTexpert_Logo_Vertical_BW[6862UL + 1];
void ShowIoTScreen(void)
{
	GUI_Clear();
	GUI_BMP_Draw(_acIOTexpert_Logo_Vertical_BW, 0,0);
	/* Send the display buffer data to display*/
	UpdateDisplay(CY_EINK_FULL_4STAGE, true);
	while(1)
		vTaskDelay(100);
}</pre>
<p>When I program the kit I get this&#8230; all black.</p>
<p>&nbsp;</p>
<p>But why?  I didn&#8217;t know the answer.  So I assumed that it must be something to do with me and my understanding of bitmaps.  In the next article I&#8217;ll tell you all about that journey.  But after a day or two of learning about bitmap file formats I was convinced that it wasn&#8217;t me.  So I started looking around on the web and I found this thread on Segger&#8217;s forum.</p>
<p><a href="https://iotexpert.com/?attachment_id=6937" rel="attachment wp-att-6937"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.36.45-AM-1024x255.png" alt="" width="1024" height="255" class="alignnone size-large wp-image-6937" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.36.45-AM-1024x255.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.36.45-AM-600x149.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.36.45-AM-300x75.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-17-at-11.36.45-AM-768x191.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And, when I got to work the next Monday I called an amazing engineer that works for Cypress in Ukraine. He provided me a v5.48 which sure enough fixed the problem.  When I program that, looks like things are working with bitmaps:</p>
<p><a href="https://iotexpert.com/?attachment_id=6929" rel="attachment wp-att-6929"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0493-1024x836.jpg" alt="" width="1024" height="836" class="alignnone size-large wp-image-6929" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0493-1024x836.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0493-600x490.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0493-300x245.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0493-768x627.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Unfortunately that means that we (Cypress) have a released version of Segger emWin that is broken.  This will be fixed with an updated version soon, but for now if you are stuck send me an email and I&#8217;ll help you.</p>
<p>The next article is a deep dive into the BMP format.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/iot-expert-logo-epd-bitmap-madness-part-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>IoT Expert Logo &#8211;&gt; EPD &#8211; Bitmap Madness (Part 1)</title>
		<link>https://iotexpert.com/iot-expert-logo-conversion-bitmap-madness-part-1/</link>
					<comments>https://iotexpert.com/iot-expert-logo-conversion-bitmap-madness-part-1/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 13 May 2019 12:00:50 +0000</pubDate>
				<category><![CDATA[CY8CKIT-028-EPD]]></category>
		<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6855</guid>

					<description><![CDATA[Summary In the last article I showed you a bunch of things about programming the Pervasive EPD eInk Display that is attached to the CY8CKIT-028-EPD.  You might have noticed in the first video I have a screen that shows the IoT Expert Logo.  Simple right?  Yes you would think, but it actually turned out to [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>In the last <a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/">article</a> I showed you a bunch of things about programming the Pervasive EPD eInk Display that is attached to the CY8CKIT-028-EPD.  You might have noticed in the first video I have a screen that shows the IoT Expert Logo.  Simple right?  Yes you would think, but it actually turned out to be quite a pain in the ass!  This article is my journey through bit maps.  It is hardly canonical, but hopefully it will help you.</p>
<p><a href="https://iotexpert.com/?attachment_id=6856" rel="attachment wp-att-6856"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0480-1024x636.jpg" alt="" width="1024" height="636" class="alignnone size-large wp-image-6856" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0480-1024x636.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0480-600x373.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0480-300x186.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0480-768x477.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>In this article I will specifically walk you through:</p>
<ul>
<li>The IoT Expert Logo</li>
<li>Segger emWin Bitmap Drawing APIs</li>
<li>Segger Bitmap Converter</li>
<li>Updating a Project to draw a Segger Bitmaps</li>
<li>Converting a Color Bitmap to Black and White</li>
<li>Using GIMP to Fix B/W Conversion</li>
</ul>
<p>In the next two articles I will address drawing bitmaps that are in the Windows BMP format and PNG format.</p>
<h1>The IoT Expert Logo</h1>
<p>If you guys remember, in early 2017, I ran a design contest to create a logo for the IoT Expert website.  You can read about it <a href="https://iotexpert.com/2017/01/16/iotexpert-logo-design-contest-part1/" target="_blank" rel="noopener noreferrer">here</a> and <a href="https://iotexpert.com/2017/02/20/new-logo-design-contest-iot-expert-part-2/" target="_blank" rel="noopener noreferrer">here</a>.  When it was over, I had a bunch of different images including this one which is a 1091&#215;739 PNG file with what I thought was five colors but is actually nine (which I discovered during this journey)</p>
<p><a href="https://iotexpert.com/?attachment_id=6857" rel="attachment wp-att-6857"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical-1024x694.png" alt="" width="1024" height="694" class="alignnone size-large wp-image-6857" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical-1024x694.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical-600x406.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical-300x203.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical-768x520.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/IOTexpert_Logo_Vertical.png 1091w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>OK, thats cool.  But how do I get that onto the eInk screen which is 276&#215;176 and black and white?</p>
<h1>emWin Bitmap Drawing APIs</h1>
<p>I started by looking at the Segger emWin documentation which you can either get directly from the Segger website <a href="https://www.segger.com/downloads/emwin/UM03001" target="_blank" rel="noopener noreferrer">here</a>.  Or you can find it inside of Modus Toolbox.  Select &#8220;Help&#8211;&gt;ModusToolbox API Reference&#8211;&gt;PSoC PDL Reference&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6894" rel="attachment wp-att-6894"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM-1024x673.png" alt="" width="1024" height="673" class="alignnone size-large wp-image-6894" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM-1024x673.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM-600x394.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM-300x197.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM-768x505.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.29.18-AM.png 1190w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Then pick &#8220;Middleware and Software API Reference &#8211;&gt; Segger emWin &#8211;&gt; emWin User Guide&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6893" rel="attachment wp-att-6893"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM-1024x768.png" alt="" width="1024" height="768" class="alignnone size-large wp-image-6893" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM-1024x768.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM-600x450.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM-300x225.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM-768x576.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-10.38.05-AM.png 1422w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>From the documentation you see that emWin can display bitmaps in the emWin format using the APIs GUI_DrawBitmap.  This section actually goes on for more than another page worth of APIs.  The API that I will focus on in this article is GUI_DrawBitmap()</p>
<p><a href="https://iotexpert.com/?attachment_id=6862" rel="attachment wp-att-6862"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.42.16-AM-1024x205.png" alt="" width="1024" height="205" class="alignnone size-large wp-image-6862" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.42.16-AM-1024x205.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.42.16-AM-600x120.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.42.16-AM-300x60.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.42.16-AM-768x153.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>You can also display bitmaps that are in GIF, PNG, BMP or JPEG format.</p>
<p><a href="https://iotexpert.com/?attachment_id=6863" rel="attachment wp-att-6863"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.39.54-AM-1024x592.png" alt="" width="1024" height="592" class="alignnone size-large wp-image-6863" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.39.54-AM-1024x592.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.39.54-AM-600x347.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.39.54-AM-300x173.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-11.39.54-AM-768x444.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Bitmap Converter for emWin</h1>
<p>I suppose the first question is, &#8220;How do I get a bitmap from my computer in PNG format into the Segger Bitmap format?&#8221;  Well, it turns out that Segger has a program called <a href="https://www.segger.com/products/user-interface/emwin/tools/tools-overview/" target="_blank" rel="noopener noreferrer">Bitmap Converter for emWin</a>.</p>
<p><a href="https://iotexpert.com/?attachment_id=6859" rel="attachment wp-att-6859"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-10.26.49-AM-1024x384.png" alt="" width="1024" height="384" class="alignnone size-large wp-image-6859" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-10.26.49-AM-1024x384.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-10.26.49-AM-600x225.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-10.26.49-AM-300x112.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-11-at-10.26.49-AM-768x288.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>This is a pay program, but you can download it to try it out.  It is sort of an old-school windows program.  So I installed it on parallels on my mac.  When you run it the first time it reminds me that this is not for production.  Got it!</p>
<p><a href="https://iotexpert.com/?attachment_id=6868" rel="attachment wp-att-6868"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.14.23-AM.png" alt="" width="992" height="452" class="alignnone size-large wp-image-6868" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.14.23-AM.png 992w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.14.23-AM-600x273.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.14.23-AM-300x137.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.14.23-AM-768x350.png 768w" sizes="auto, (max-width: 992px) 100vw, 992px" /></a></p>
<p>I start by opening the PNG file of my logo.  Notice that it says the file is 1091 by 739 and in &#8220;ARGB&#8221; colors.  &#8220;ARGB&#8221; means Alpha, Red, Green and Blue. (more on this later).</p>
<p><a href="https://iotexpert.com/?attachment_id=6867" rel="attachment wp-att-6867"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM-1024x880.png" alt="" width="1024" height="880" class="alignnone size-large wp-image-6867" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM-1024x880.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM-600x515.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM-300x258.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM-768x660.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.06-AM.png 1404w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>On the Image menu I start by picking &#8220;Scale..&#8221; to reduce the size.</p>
<p><a href="https://iotexpert.com/?attachment_id=6866" rel="attachment wp-att-6866"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.26-AM.png" alt="" width="542" height="580" class="alignnone size-large wp-image-6866" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.26-AM.png 542w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.26-AM-280x300.png 280w" sizes="auto, (max-width: 542px) 100vw, 542px" /></a></p>
<p>I pick out 276 wide and it keeps the aspect ratio the same, which results in a height of 186 (actually 10 pixels to high)</p>
<p><a href="https://iotexpert.com/?attachment_id=6865" rel="attachment wp-att-6865"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.37-AM.png" alt="" width="454" height="376" class="alignnone size-full wp-image-6865" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.37-AM.png 454w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.15.37-AM-300x248.png 300w" sizes="auto, (max-width: 454px) 100vw, 454px" /></a></p>
<p>After clicking OK I get this.</p>
<p><a href="https://iotexpert.com/?attachment_id=6869" rel="attachment wp-att-6869"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.17.45-AM.png" alt="" width="760" height="620" class="alignnone size-full wp-image-6869" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.17.45-AM.png 760w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.17.45-AM-600x489.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.17.45-AM-300x245.png 300w" sizes="auto, (max-width: 760px) 100vw, 760px" /></a></p>
<p>Now, I want to take that bitmap and turn it into a &#8220;C&#8221; file that has the right data structures.  To do that pick &#8220;Save As..&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6873" rel="attachment wp-att-6873"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.19.47-AM.png" alt="" width="1014" height="224" class="alignnone size-large wp-image-6873" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.19.47-AM.png 1014w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.19.47-AM-600x133.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.19.47-AM-300x66.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.19.47-AM-768x170.png 768w" sizes="auto, (max-width: 1014px) 100vw, 1014px" /></a></p>
<p>Then pick &#8220;C&#8221; bitmap file (*.c)</p>
<p><a href="https://iotexpert.com/?attachment_id=6872" rel="attachment wp-att-6872"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM-1024x765.png" alt="" width="1024" height="765" class="alignnone size-large wp-image-6872" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM-1024x765.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM-600x448.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM-300x224.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM-768x574.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.20.11-AM.png 1106w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now, it asks me this question, which I didn&#8217;t really know the answer to. (more on this later) but I let the default be &#8220;True color with alpha&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6871" rel="attachment wp-att-6871"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.25.06-AM.png" alt="" width="606" height="456" class="alignnone size-large wp-image-6871" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.25.06-AM.png 606w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.25.06-AM-600x451.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.25.06-AM-300x226.png 300w" sizes="auto, (max-width: 606px) 100vw, 606px" /></a></p>
<p>This created a &#8220;C&#8221; file called IOTexpert_Logo_Vertical.c&#8221; which seems to be OK.</p>
<h1>Updating a Project to draw a Segger Bitmap</h1>
<p>Rather than make a new project.  I start with the project from the previous article.  I use the finder to copy/paste the c file into my project.  You can see it below.</p>
<p><a href="https://iotexpert.com/?attachment_id=6870" rel="attachment wp-att-6870"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.34.43-AM.png" alt="" width="920" height="682" class="alignnone size-full wp-image-6870" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.34.43-AM.png 920w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.34.43-AM-600x445.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.34.43-AM-300x222.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-8.34.43-AM-768x569.png 768w" sizes="auto, (max-width: 920px) 100vw, 920px" /></a></p>
<p>Then I double click on the file.  Here is the top.  Notice it reminds me that this is demo only.  And it gives me a little bit of information about the bitmap.  Specifically the width and height.  As well as the number of colors which is 32 bits per pixel.  It turns out that this is 4-bytes per pixel.  The first byte is Alpha and then one byte each for Red, Green and Blue.  Notice that it also declares an extern structure &#8220;extern GUI_CONST_STORAGE GUI_BITMAP bmIOTexpert_Logo_Vertical&#8221;.  This is exactly the right type to call the GUI_Drawbitmap function.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">/*********************************************************************
*                SEGGER Microcontroller GmbH &amp; Co. KG                *
*        Solutions for real time microcontroller applications        *
*                           www.segger.com                           *
**********************************************************************
*                                                                    *
* C-file generated by                                                *
*                                                                    *
*        Bitmap Converter for emWin (Demo version) V5.48.            *
*        Compiled Jun 12 2018, 15:10:41                              *
*                                                                    *
*        (c) 1998 - 2018 Segger Microcontroller GmbH                 *
*                                                                    *
*        May not be used in a product                                *
*                                                                    *
**********************************************************************
*                                                                    *
* Source file: IOTexpert_Logo_Vertical                               *
* Dimensions:  276 * 186                                             *
* NumColors:   32bpp: 16777216 + 256                                 *
*                                                                    *
**********************************************************************
*/

#include &lt;stdlib.h&gt;

#include "GUI.h"

#ifndef GUI_CONST_STORAGE
  #define GUI_CONST_STORAGE const
#endif

extern GUI_CONST_STORAGE GUI_BITMAP bmIOTexpert_Logo_Vertical;

static GUI_CONST_STORAGE U32 _acIOTexpert_Logo_Vertical[] = {
  0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 
</pre>
<p>In my project I create a new function called &#8220;ShowIoT&#8221; screen.  This will just clear the screen, update the display, then draw the bitmap, then update the screen, then wait forever.  In order for my file to know about the bitmap I copy the &#8220;extern GUI_CONST_STORAGE GUI_BITMAP bmIOTexpert_Logo_Vertical&#8221; into my file.  Typically this declaration would be in a &#8220;.h&#8221; file that was paired with the &#8220;.c&#8221; file.  Oh well.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">extern GUI_CONST_STORAGE GUI_BITMAP bmCypressLogoFullColor_PNG_1bpp;

void ShowIoTScreen(void)
{
    /* Set foreground and background color and font size */
    GUI_Clear();
    GUI_SetBkColor(GUI_WHITE);
    GUI_SetColor(GUI_BLACK);
    UpdateDisplay(CY_EINK_FULL_4STAGE, true);

    GUI_DrawBitmap(&amp;bmCypressLogoFullColor_PNG_1bpp, 0, 0);

    /* Send the display buffer data to display*/
    UpdateDisplay(CY_EINK_FULL_4STAGE, true);
    while(1)
    	vTaskDelay(100);
}
</pre>
<p>When I build the project I find out.. HOLY CRAP my project is now 270648 bytes.  Wow.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">=========================================
== Application CM0+ Memory ==
=========================================
code:6560	sram:1724


=========================================
== Application CM4 Memory ==
=========================================
code:270648	sram:278508

</pre>
<p>Why is this?  Simple, by looking at the linker map you can see that the array of data for the bitmap is 0x32220 which is also known as <span>205344 bytes.  Im going to have to figure out something better than that.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c"> .rodata._acIOTexpert_Logo_Vertical
                0x0000000000000000    0x32220 ./Source/IOTexpert_Logo_Vertical.o</pre>
<p>When I program the screen I get this&#8230; which obviously is jacked up.</p>
<p><a href="https://iotexpert.com/?attachment_id=6879" rel="attachment wp-att-6879"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0482-2-1024x872.jpg" alt="" width="1024" height="872" class="alignnone size-large wp-image-6879" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0482-2-1024x872.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0482-2-600x511.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0482-2-300x256.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0482-2-768x654.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>But what to do?</p>
<h1>Converting a Color Bitmap to Black and White</h1>
<p>Well instead of a color image (32 bits-per-pixel) let&#8217;s use the Bitmap Converter for emWin (Demo version V5.8 to convert the image to BW.  On the Image &#8211;&gt;Covert to &#8211;&gt; BW (1BPP)</p>
<p><a href="https://iotexpert.com/?attachment_id=6877" rel="attachment wp-att-6877"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM-1024x879.png" alt="" width="1024" height="879" class="alignnone size-large wp-image-6877" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM-1024x879.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM-600x515.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM-300x257.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM-768x659.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.17-AM.png 1156w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>After running that I get this. (what happened to my logo?).</p>
<p><a href="https://iotexpert.com/?attachment_id=6876" rel="attachment wp-att-6876"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM-1024x889.png" alt="" width="1024" height="889" class="alignnone size-large wp-image-6876" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM-1024x889.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM-600x521.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM-300x261.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM-768x667.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.11.30-AM.png 1400w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><br />
After exporting the new image to a &#8220;.c&#8221; file I go have a look.  OK it isnt very often that I learn something new about &#8220;C&#8221;.  But look at this.  Apparently you can represent binary data as &#8220;X&#8221; and &#8220;_&#8221; when initializing arrays.  Who knew?</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">static GUI_CONST_STORAGE unsigned char _acIOTexpert_Logo_Vertical[] = {
  XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, 
        XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXX____,
</pre>
<p>When I build the project I find that it is much much smaller.  Thats good.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">=========================================
== Application CM0+ Memory ==
=========================================
code:6560	sram:1724


=========================================
== Application CM4 Memory ==
=========================================
code:69744	sram:278492

</pre>
<p>And I find that the image occupies 0x196e bytes (also known as 6510 in decimal).  Much better.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">.rodata._acIOTexpert_Logo_Vertical
                0x000000001000f880     0x196e ./Source/IOTexpert_Logo_Vertical.o</pre>
<p>But, when I program the board, my image is jacked up.  I suppose that I shouldn&#8217;t be surprised as thats what the program showed me as well.</p>
<p><a href="https://iotexpert.com/?attachment_id=6880" rel="attachment wp-att-6880"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0483-1024x859.jpg" alt="" width="1024" height="859" class="alignnone size-large wp-image-6880" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0483-1024x859.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0483-600x504.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0483-300x252.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0483-768x645.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Using GIMP to Fix B/W Conversion</h1>
<p>My lab assistant, Nicholas, looked at the image and said.  The problem is that when you converted it to black and white, the light colors in the logo turned to white instead of black.  OK.  How do I fix it?  Simple, install <a href="https://www.gimp.org" target="_blank" rel="noopener noreferrer">GIMP</a> and edit the PNG.  GIMP is GNU Image Processor and is a program that acts like Adobe Photoshop.</p>
<p>Start by opening up the logo and it tell me nearly the same thing as the BitMap converter program.</p>
<p><a href="https://iotexpert.com/?attachment_id=6885" rel="attachment wp-att-6885"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.36.13-AM-1024x645.png" alt="" width="1024" height="645" class="alignnone size-large wp-image-6885" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.36.13-AM-1024x645.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.36.13-AM-600x378.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.36.13-AM-300x189.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.36.13-AM-768x484.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>On the left side of the screen there is a &#8220;bucket&#8221; icon which will pour color into regions of the image.  So, to make things work I pour black everywhere there is color.  That little black white thing specifies the foreground and background colors.</p>
<p><a href="https://iotexpert.com/?attachment_id=6883" rel="attachment wp-att-6883"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.13-AM-1024x642.png" alt="" width="1024" height="642" class="alignnone size-large wp-image-6883" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.13-AM-1024x642.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.13-AM-600x376.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.13-AM-300x188.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.13-AM-768x482.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now I take the file and export it back to an PNG.</p>
<p><a href="https://iotexpert.com/?attachment_id=6882" rel="attachment wp-att-6882"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.27-AM.png" alt="" width="612" height="854" class="alignnone size-large wp-image-6882" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.27-AM.png 612w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.27-AM-600x837.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.39.27-AM-215x300.png 215w" sizes="auto, (max-width: 612px) 100vw, 612px" /></a></p>
<p>When you pick &#8220;PNG&#8221; you need to give it some options.  Which I took also as default.</p>
<p><a href="https://iotexpert.com/?attachment_id=6881" rel="attachment wp-att-6881"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.40.39-AM.png" alt="" width="580" height="920" class="alignnone size-full wp-image-6881" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.40.39-AM.png 580w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.40.39-AM-189x300.png 189w" sizes="auto, (max-width: 580px) 100vw, 580px" /></a></p>
<p>Now when I open it up in the Bitmap Converter it looks all black and white.  BUT notice that it is still &#8220;ARGB&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6886" rel="attachment wp-att-6886"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.44.16-AM.png" alt="" width="878" height="798" class="alignnone size-full wp-image-6886" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.44.16-AM.png 878w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.44.16-AM-600x545.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.44.16-AM-300x273.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.44.16-AM-768x698.png 768w" sizes="auto, (max-width: 878px) 100vw, 878px" /></a></p>
<p>So, I convert it to black and white.</p>
<p><a href="https://iotexpert.com/?attachment_id=6887" rel="attachment wp-att-6887"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.45.24-AM.png" alt="" width="906" height="822" class="alignnone size-full wp-image-6887" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.45.24-AM.png 906w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.45.24-AM-600x544.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.45.24-AM-300x272.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-12-at-9.45.24-AM-768x697.png 768w" sizes="auto, (max-width: 906px) 100vw, 906px" /></a></p>
<p>Then I follow the same process to program the development kit. (export C file, copy into project, fix up the extern and build/program).  Excellent.  Now my image is good.</p>
<p><a href="https://iotexpert.com/?attachment_id=6890" rel="attachment wp-att-6890"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0484-1024x806.jpg" alt="" width="1024" height="806" class="alignnone size-large wp-image-6890" srcset="https://iotexpert.com/wp-content/uploads/2019/05/IMG_0484-1024x806.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0484-600x472.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0484-300x236.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/05/IMG_0484-768x604.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>In the next article I will talk more about the Bitmap format, and colors, and Alpha.  I will then show you how to use some of the other APIs.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/iot-expert-logo-conversion-bitmap-madness-part-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CY8CKIT-028-EPD:  How Does The Driver Work?</title>
		<link>https://iotexpert.com/cy8ckit-028-epd-how-does-the-driver-work/</link>
					<comments>https://iotexpert.com/cy8ckit-028-epd-how-does-the-driver-work/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Fri, 10 May 2019 15:02:39 +0000</pubDate>
				<category><![CDATA[CY8CKIT-028-EPD]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PSoC 6]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6826</guid>

					<description><![CDATA[Summary Before I finish this series there are two more issues which I would like to address.  First, I want to walk you through the schematic and show you how things are connected.  And second, I want to talk about the &#8220;Update Scheme&#8221;.  Unfortunately, there are a couple of other things that I would like [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>Before I finish this series there are two more issues which I would like to address.  First, I want to walk you through the schematic and show you how things are connected.  And second, I want to talk about the &#8220;Update Scheme&#8221;.  Unfortunately, there are a couple of other things that I would like to dig into, but for now this article will be the last.  But, I will leave a few links at the end of the article which will give you a hint about other things that I might be interested in.</p>
<h1>Electrical Interface</h1>
<p>If you follow back through the previous articles you will notice that there are several different pins.  Here is the pin assignment from PSoC Creator.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-09-03-pm/" rel="attachment wp-att-6687"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM.png" alt="" width="670" height="297" class="alignnone size-full wp-image-6687" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM.png 670w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM-600x266.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM-300x133.png 300w" sizes="auto, (max-width: 670px) 100vw, 670px" /></a></p>
<p>But what do they do?  If you look at the list you will see that four of them are to control the SPI interface to the G2 display driver. (miso, mosi, sclk, CY_EINK_Ssel).  The rest of them Ill go one by one through.</p>
<p>First is the pin called &#8220;CY_EINK_DispEn&#8221;.  This pin really should have been called &#8220;DISP_PWR_EN&#8221; so that it matched the actual shield schematic.  This is a digital output pin which is connected to a <a href="https://www.vishay.com/docs/63705/sip32401a.pdf" target="_blank" rel="noopener noreferrer">Vishay sip32401a 1.1 V to 5.5 V, Slew Rate Controlled Load Switch</a>.  Simply a power switch for the display.  Notice in the schematic that there is a 100K pulldown resistor connected to the enable which means that by default the power is off to the display.  Also notice that R3 is a &#8220;No Load&#8221; pullup resistor.  You could remove R4 and load R3 to make the power on by default&#8230; which I don&#8217;t think that you would actually ever do as if you are using an EPD you probably care about power.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-9-47-19-am/" rel="attachment wp-att-6839"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.47.19-AM.png" alt="" width="535" height="292" class="alignnone size-full wp-image-6839" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.47.19-AM.png 535w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.47.19-AM-300x164.png 300w" sizes="auto, (max-width: 535px) 100vw, 535px" /></a></p>
<p>The next pin is called &#8220;CY_EINK_DispIoEn&#8221;.  This is a digital output pin which is connected to &#8220;DISP_IO_EN_L&#8221; on the shield.  This is simply the I/O enable of a Fairchild <a href="https://www.onsemi.com/pub/Collateral/FXMA108-D.pdf" target="_blank" rel="noopener noreferrer">FXMA108BQX</a> level shifter.  This allows the PSoC to run at lower voltages (e.g. 1.8v) than the 3.3v required by the EPD G2 driver chip.  This would also enable a chip to run at a higher voltage (e.g. 5V) if you were using a 5V capable PSoC (e.g. all of the PSoC 4s).  The schematic uses the same pullup/down scheme that was used on the power switch above.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-9-43-59-am/" rel="attachment wp-att-6838"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.43.59-AM.png" alt="" width="533" height="373" class="alignnone size-full wp-image-6838" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.43.59-AM.png 533w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.43.59-AM-300x210.png 300w" sizes="auto, (max-width: 533px) 100vw, 533px" /></a></p>
<p>The next pin is called &#8220;CY_EINK_Discharge&#8221; and is a digital output from the PSoC.  Notice that when the PSoC drives this pin high that it will enable two power transistors and will short &#8220;VGH&#8221; and &#8220;VDH&#8221; to ground.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-9-49-53-am/" rel="attachment wp-att-6841"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.49.53-AM.png" alt="" width="347" height="295" class="alignnone size-large wp-image-6841" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.49.53-AM.png 347w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.49.53-AM-300x255.png 300w" sizes="auto, (max-width: 347px) 100vw, 347px" /></a></p>
<p>If you read the &#8220;E-paper Display COG Driver Interface Timing for 1.44”,1.9”,2”,2.6” and 2.7” EPD with G2 COG and Aurora Mb Film&#8221; document you will see this note:</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-11-17-23-am/" rel="attachment wp-att-6845"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.23-AM.png" alt="" width="602" height="78" class="alignnone size-large wp-image-6845" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.23-AM.png 602w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.23-AM-600x78.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.23-AM-300x39.png 300w" sizes="auto, (max-width: 602px) 100vw, 602px" /></a></p>
<p>And a bit later on in the documented you will see this logic diagram.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-11-17-49-am/" rel="attachment wp-att-6844"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM-1024x563.png" alt="" width="1024" height="563" class="alignnone size-large wp-image-6844" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM-1024x563.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM-600x330.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM-300x165.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM-768x422.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.17.49-AM.png 1145w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>According to the data sheet, Vgh is driven to &gt;12v and Vdh&gt;8v by a charge pump while talking to the screen.  What I don&#8217;t understand is why the note says to drive &#8220;Vdd and Vcc&#8221; to ground when their schematic says Vdh and Vgh.  I am assuming that the note is an error and the schematic is correct, but Ill send them a note and ask. [edit: I got a quick response from an excellent FAE at Pervasive&#8230; with this answer]</p>
<p>&#8220;No, the expression of Note 1 about Vcc/Vdd, it means the power off command set. You can also refer to Power off sequence in section 6 on page 34 of 4P018-00 as follows&#8221;</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/thumbnail_image002/" rel="attachment wp-att-6849"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002-1024x584.png" alt="" width="1024" height="584" class="alignnone size-large wp-image-6849" srcset="https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002-1024x584.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002-600x342.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002-300x171.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002-768x438.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/thumbnail_image002.png 1105w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The last digital I/O pin is called &#8220;CY_EINK_Border&#8221;.  This pin is connected to the note &#8220;EPD_BRDR_CTRL&#8221; on this little circuit on the shield.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-9-50-00-am/" rel="attachment wp-att-6840"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.50.00-AM.png" alt="" width="348" height="375" class="alignnone size-full wp-image-6840" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.50.00-AM.png 348w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-9.50.00-AM-278x300.png 278w" sizes="auto, (max-width: 348px) 100vw, 348px" /></a></p>
<p>If you look in the documentation you will see this note:</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-11-33-45-am/" rel="attachment wp-att-6846"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.33.45-AM.png" alt="" width="1002" height="135" class="alignnone size-full wp-image-6846" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.33.45-AM.png 1002w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.33.45-AM-600x81.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.33.45-AM-300x40.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.33.45-AM-768x103.png 768w" sizes="auto, (max-width: 1002px) 100vw, 1002px" /></a></p>
<p>And when you look at the timing diagram you see this which shows that after you have update the frame, that you need to do a low, high, low of the border to make it white again.</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-09-at-11-37-23-am/" rel="attachment wp-att-6847"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.37.23-AM.png" alt="" width="956" height="749" class="alignnone size-full wp-image-6847" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.37.23-AM.png 956w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.37.23-AM-600x470.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.37.23-AM-300x235.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-09-at-11.37.23-AM-768x602.png 768w" sizes="auto, (max-width: 956px) 100vw, 956px" /></a></p>
<p>This transition is handled for you by the function &#8220;Pv_EINK_HardwarePowerOff&#8221; function&#8230; which I chopped out a little bit of to show the border control.</p>
<pre class="lang:c decode:true ">pv_eink_status_t Pv_EINK_HardwarePowerOff(void)
{
.....
    
    /* After E-INK updates, the border color may degrade to a gray level that is not
    as white as the active area. Toggle the Border pin to avoid this phenomenon. */
    CY_EINK_Delay(PV_EINK_DUMMY_LINE_DELAY);
    CY_EINK_BorderLow;
    CY_EINK_Delay(PV_EINK_BOARDER_DELAY);
    CY_EINK_BorderHigh;

...
turn of the G2    
....

    /* Detach SPI and disable the load switch connected to E-INK display's Vcc */
    Cy_EINK_DetachSPI();
    CY_EINK_TurnOffVcc;
    
    /* Return the pins to their default (OFF) values*/
    CY_EINK_BorderLow;
    CY_EINK_Delay(PV_EINK_CS_OFF_DELAY);
    CY_EINK_CsLow;
    CY_EINK_RstLow;
    CY_EINK_DischargeHigh;
    CY_EINK_Delay(PV_EINK_DETACH_DELAY);
    CY_EINK_DischargeLow;
    
    /* If all operations were completed successfully, send the corresponding flag */
    return(PV_EINK_RES_OK);
}</pre>
<h1>Update Scheme</h1>
<p>If you look at the original picture that I posted,  you can see that &#8220;Hassane&#8230;&#8221; text.  But if you look closely you can see a &#8220;ghost image&#8221; of the Cypress logo in the background.  Why is this?</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/img_0408/" rel="attachment wp-att-6668"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-1024x768.jpg" alt="" width="1024" height="768" class="alignnone size-large wp-image-6668" srcset="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-scaled-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>It turns out that Pervasive has three schemes for updating the screen they are called</p>
<ol>
<li>Four stage</li>
<li>Two stage</li>
<li>Partial</li>
</ol>
<p>The four stage update actually writes four complete images on the screen as below (here is the picture from the Pervasive document)</p>
<p><a href="https://iotexpert.com/2019/05/10/cy8ckit-028-epd-how-does-the-driver-work/screen-shot-2019-05-07-at-6-41-59-am/" rel="attachment wp-att-6834"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM-1024x384.png" alt="" width="1024" height="384" class="alignnone size-large wp-image-6834" srcset="https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM-1024x384.png 1024w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM-600x225.png 600w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM-300x113.png 300w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM-768x288.png 768w, https://iotexpert.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-07-at-6.41.59-AM.png 1552w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The purpose of this four stage update is to reduce the ghost images which remain from the previous updates.  Remember that the cool part about these screens is that there are crystals that flip from white to black and back&#8230; and once they are flipped you do not need to maintain power to keep them flipped.  The bad news is that they really want to stay flipped which causes Ghosting.</p>
<p>So why can you see the old image of the Cypress logo?  Simple,  when the four-stage update happened, I had just programmed the kit which means that my program had no idea what was on the screen from before.  This made stage 1 not work correctly because it had to assume all white.</p>
<p>The next question is what is the problem with the four-stage update?  Well it takes a while (like about 2 seconds) on the 2.7&#8243; screen.  And because it writes 4 times it also consumes more power.  Pervasive also says that you can do a two-stage update with just stage 1 and stage 4 from above.  In my case this cuts the time in about half.</p>
<p>Finally you can also do a &#8220;partial&#8221; update.  I tried this and it didn&#8217;t work very well for my demo application which massively changes the screen from screen to screen.  But, it does seem to work pretty well for a series of updates to the same reigon (like this counter).  Here is a video I made showing Partial, Two and Four stage updates.   In addition our API lets you turn the power on/off for the G2 Driver &#8211; called &#8220;power cycle&#8221;.  I used that as a variable as well.</p>
<div class="jupiterx-oembed"><iframe loading="lazy" title="CY8CKIT-028-EPD emWin EPD Update Speed" width="500" height="281" src="https://www.youtube.com/embed/IFwcekb7GkQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></div>
<h1>Terms of Art</h1>
<p>EPD &#8211; Electrophoretic Display</p>
<p>eTC &#8211; external timing control</p>
<p>iTC &#8211; internal timing control</p>
<p>G2 COG &#8211; Display Controller Chip&#8230; Chip on Glass</p>
<p>FPL &#8211; Front Plane Laminate (of which Aurora ma and mb are two types)</p>
<p>Aurora ma &#8211; Wide Temperature film</p>
<p>Aurora mb &#8211; Low power</p>
<p>E2271CS021 &#8211; Aurora mb 2.71&#8243; EPD Panel &#8211; on CY8CKIT-028-EPD</p>
<p>E2271BS021 &#8211; Aurora ma 2.71&#8243; EPD Panel</p>
<h1>References</h1>
<p>mbed add http://os.mbed.com/users/dreschpe/code/EaEpaper/</p>
<p>http://www.pervasivedisplays.com/kits/ext2_kit</p>
<p>https://www.nayuki.io/page/pervasive-displays-epaper-panel-hardware-driver</p>
<p>https://github.com/nayuki/Pervasive-Displays-epaper-driver</p>
<p>https://github.com/repaper/gratis</p>
<p>https://github.com/aerialist/repaper_companion</p>
<p>https://www.paulschow.com/2017/02/pervasive-displays-epd-extension-kit.html</p>
<p>https://embeddedcomputing.weebly.com/pervasive-displays-e-paper-epd-extension-kit-gen-2.html</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/cy8ckit-028-epd-how-does-the-driver-work/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CY8CKIT-028-EPD Better Timing</title>
		<link>https://iotexpert.com/cy8ckit-028-epd-better-timing/</link>
					<comments>https://iotexpert.com/cy8ckit-028-epd-better-timing/#comments</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 29 Apr 2019 12:00:44 +0000</pubDate>
				<category><![CDATA[CY8CKIT-062-BLE]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PSoC 6]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6804</guid>

					<description><![CDATA[Summary In the first article of this series I talked about how to make the CY8CKIT-028-EPD EINK Shield work with PSoC 6 and Modus Toolbox 1.1. In the second article I improved the interface and talked about the PSoC 6 clocking system.  In this article I want to address the timing system in the EINK [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>In the <a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/" target="_blank" rel="noopener noreferrer">first article</a> of this series I talked about how to make the CY8CKIT-028-EPD EINK Shield work with PSoC 6 and Modus Toolbox 1.1. In the <a href="https://iotexpert.com/2019/04/21/cy8ckit-028-eink-mo-better/">second article</a> I improved the interface and talked about the PSoC 6 clocking system.  In this article I want to address the timing system in the EINK firmware.  You might recall that I used one of the Timer-Counter-Pulse-Width-Modulator blocks a.k.a the TCPWM inside of the PSoC 6 as a Timer for updating the EINK Screen.  Using this timer was a bit of a waste as the CM4 already has a timer built into the device called the SysTick timer.  Moreover, the SysTick timer is connected to the FreeRTOS timing system which provides you APIs to talk to it.  For this article I will talk about:</p>
<ul>
<li>ARM SysTick</li>
<li>Cypress PDL and SysTick</li>
<li>FreeRTOS and SysTick</li>
<li>Make a new project &amp; copy the files</li>
<li>Use the FreeRTOS timing system to measure the speed increase of the updated SPI</li>
<li>Remove the hardware timer &amp; replace with the RTOS timer.</li>
</ul>
<h1>ARM SysTick</h1>
<p>The ARM Cortex-M MCUs have an option to include a 24-bit timer called SysTick.  As best I can tell, every MCU maker always chooses to have the SysTick option built in.   Certainly the PSoC 4 and PSoC 6 family all have it built in.   But how do you talk to it?  Well, my buddy Reinhard Keil decided that it was silly for everyone to create a different method for interacting with standard ARM peripherals so he created the Cortex Microcontroller Software Interface Standard (CMSIS)</p>
<p><a href="https://iotexpert.com/?attachment_id=6808" rel="attachment wp-att-6808"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/IMG_5752-1024x769.jpg" alt="" width="1024" height="769" class="alignnone size-large wp-image-6808" srcset="https://iotexpert.com/wp-content/uploads/2019/04/IMG_5752-1024x769.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_5752-600x451.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_5752-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_5752-768x577.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="https://www.keil.com/pack/doc/cmsis/Core/html/group__SysTick__gr.html" target="_blank" rel="noopener noreferrer">CMSIS defines</a> two things that you need to do to make the SysTick timer work.  First, you need to create a function called EXACTLY &#8220;SysTick_Handler&#8221;.  This function gets loaded into the vector table of your program as the interrupt handler for the SysTick interrupt.  As such the function prototype is &#8220;void SysTick_Handler(void)&#8221;.  The second thing that you need to do is initialize how often the timer should be called.  You do this with the CMSIS call:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">SysTick_Config(SystemCoreClock/1000);</pre>
<p>It is interesting to note that the symbol SystemCoreClock is also defined by CMSIS as the frequency of the clock.  So the above call would setup the SysTick to be called every 1Ms (that is why there is a divide by 1000).</p>
<p>Here is an example I created starting with the BlinkyLED example project.  After I created the project, I added the kitprog uart (which is SCB5) and I added the Retarget I/O middleware.</p>
<pre class="lang:c decode:true ">#include "cy_pdl.h"
#include "cycfg.h"
#include &lt;stdio.h&gt;

volatile uint32_t count;

void SysTick_Handler(void)
{
	count += 1;
}
cy_stc_scb_uart_context_t kitprog_context;

int main(void)
{
	Cy_SCB_UART_Init(kitprog_HW,&amp;kitprog_config,&amp;kitprog_context);
	Cy_SCB_UART_Enable(kitprog_HW);
    /* Set up internal routing, pins, and clock-to-peripheral connections */
    init_cycfg_all();
    
    SysTick_Config(SystemCoreClock/1000);

    /* enable interrupts */
    __enable_irq();

    for (;;)
    {
    		printf("Test count=%d\n",(int)count);
        Cy_GPIO_Inv(LED_RED_PORT, LED_RED_PIN); /* toggle the pin */
        Cy_SysLib_Delay(1000/*msec*/);
    }
}
</pre>
<p>Don&#8217;t forget to setup the standard i/o by modifying stdio_user.h</p>
<pre class="start-line:172 EnlighterJSRAW" data-enlighter-language="c"">#include "cycfg.h"
/* Must remain uncommented to use this utility */
#define IO_STDOUT_ENABLE
#define IO_STDIN_ENABLE
#define IO_STDOUT_UART      kitprog_HW
#define IO_STDIN_UART       kitprog_HW</pre>
<p>When you run the program above you should get something like this:</p>
<p><a href="https://iotexpert.com/?attachment_id=6809" rel="attachment wp-att-6809"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM-1024x702.png" alt="" width="1024" height="702" class="alignnone size-large wp-image-6809" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM-1024x702.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM-600x411.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM-300x206.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM-768x526.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.05.09-AM.png 1202w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>One interesting question is HOW does the function SysTick_Handler get into the vector table?  Well if you run an eclipse search (type ctrl-h)</p>
<p><a href="https://iotexpert.com/?attachment_id=6810" rel="attachment wp-att-6810"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM-1024x846.png" alt="" width="1024" height="846" class="alignnone size-large wp-image-6810" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM-1024x846.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM-600x496.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM-300x248.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM-768x635.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.10.23-AM.png 1140w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>You will find it in an assembly language file called &#8220;startup_psoc6_01_cm4.s&#8221;</p>
<p><a href="https://iotexpert.com/?attachment_id=6811" rel="attachment wp-att-6811"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM-1024x333.png" alt="" width="1024" height="333" class="alignnone size-large wp-image-6811" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM-1024x333.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM-600x195.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM-300x98.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM-768x250.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.11.06-AM.png 1450w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Double click on the file and you can see the Vector table.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">__Vectors:
    .long    __StackTop            /* Top of Stack */
    .long    Reset_Handler         /* Reset Handler */
    .long    CY_NMI_HANLDER_ADDR   /* NMI Handler */
    .long    HardFault_Handler     /* Hard Fault Handler */
    .long    MemManage_Handler     /* MPU Fault Handler */
    .long    BusFault_Handler      /* Bus Fault Handler */
    .long    UsageFault_Handler    /* Usage Fault Handler */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    SVC_Handler           /* SVCall Handler */
    .long    DebugMon_Handler      /* Debug Monitor Handler */
    .long    0                     /* Reserved */
    .long    PendSV_Handler        /* PendSV Handler */
    .long    SysTick_Handler       /* SysTick Handler */</pre>
<p>But how do the _Vectors get into the right place?  Well? run the search again and you will find that the linker script (which Cypress created) for your project has the definition.</p>
<p><a href="https://iotexpert.com/?attachment_id=6813" rel="attachment wp-att-6813"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM-1024x775.png" alt="" width="1024" height="775" class="alignnone size-large wp-image-6813" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM-1024x775.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM-600x454.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM-300x227.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM-768x582.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.13.43-AM.png 1376w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>When you look in the linker script you can see that it is installed at the top of the flash</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">    {
        . = ALIGN(4);
        __Vectors = . ;
        KEEP(*(.vectors))
        . = ALIGN(4);
        __Vectors_End = .;
        __Vectors_Size = __Vectors_End - __Vectors;
        __end__ = .;

        . = ALIGN(4);
        *(.text*)

        KEEP(*(.init))
        KEEP(*(.fini))

        /* .ctors */
        *crtbegin.o(.ctors)
        *crtbegin?.o(.ctors)
        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
        *(SORT(.ctors.*))
        *(.ctors)

        /* .dtors */
        *crtbegin.o(.dtors)
        *crtbegin?.o(.dtors)
        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
        *(SORT(.dtors.*))
        *(.dtors)

        /* Read-only code (constants). */
        *(.rodata .rodata.* .constdata .constdata.* .conststring .conststring.*)

        KEEP(*(.eh_frame*))
    } &gt; flash</pre>
<p>And the CM4 flash is defined to start at 0x100002000</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">MEMORY
{
    /* The ram and flash regions control RAM and flash memory allocation for the CM4 core.
     * You can change the memory allocation by editing the 'ram' and 'flash' regions.
     * Note that 2 KB of RAM (at the end of the RAM section) are reserved for system use.
     * Using this memory region for other purposes will lead to unexpected behavior.
     * Your changes must be aligned with the corresponding memory regions for CM0+ core in 'xx_cm0plus.ld',
     * where 'xx' is the device group; for example, 'cy8c6xx7_cm0plus.ld'.
     */
    ram               (rwx)   : ORIGIN = 0x08002000, LENGTH = 0x45800
    flash             (rx)    : ORIGIN = 0x10002000, LENGTH = 0xFE000

    /* This is a 32K flash region used for EEPROM emulation. This region can also be used as the general purpose flash.
     * You can assign sections to this memory region for only one of the cores.
     * Note some middleware (e.g. BLE, Emulated EEPROM) can place their data into this memory region.
     * Therefore, repurposing this memory region will prevent such middleware from operation.
     */
    em_eeprom         (rx)    : ORIGIN = 0x14000000, LENGTH = 0x8000       /*  32 KB */

    /* The following regions define device specific memory regions and must not be changed. */
    sflash_user_data  (rx)    : ORIGIN = 0x16000800, LENGTH = 0x800        /* Supervisory flash: User data */
    sflash_nar        (rx)    : ORIGIN = 0x16001A00, LENGTH = 0x200        /* Supervisory flash: Normal Access Restrictions (NAR) */
    sflash_public_key (rx)    : ORIGIN = 0x16005A00, LENGTH = 0xC00        /* Supervisory flash: Public Key */
    sflash_toc_2      (rx)    : ORIGIN = 0x16007C00, LENGTH = 0x200        /* Supervisory flash: Table of Content # 2 */
    sflash_rtoc_2     (rx)    : ORIGIN = 0x16007E00, LENGTH = 0x200        /* Supervisory flash: Table of Content # 2 Copy */
    xip               (rx)    : ORIGIN = 0x18000000, LENGTH = 0x8000000    /* 128 MB */
    efuse             (r)     : ORIGIN = 0x90700000, LENGTH = 0x100000     /*   1 MB */
}</pre>
<p>And when you look at the linker MAP file which is in your project Debug/BlinkyLED_mainapp.map you will see that the vectors end up in the right place.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">.text           0x0000000010002000     0x5de4
                0x0000000010002000                . = ALIGN (0x4)
                0x0000000010002000                __Vectors = .
</pre>
<h1>Cypress SysTick</h1>
<p>Now if you happen to be reading the PDL documentation on Saturday afternoon you might notice that there is a section of the documentation called &#8220;SysTick&#8221;.  And when you click it you will find this:</p>
<p><a href="https://iotexpert.com/?attachment_id=6815" rel="attachment wp-att-6815"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.22.52-AM.png" alt="" width="824" height="758" class="alignnone size-full wp-image-6815" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.22.52-AM.png 824w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.22.52-AM-600x552.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.22.52-AM-300x276.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.22.52-AM-768x706.png 768w" sizes="auto, (max-width: 824px) 100vw, 824px" /></a></p>
<p>And you might ask yourself &#8220;What the hell.. those aren&#8217;t CMSIS functions?&#8221;  Well in typical Cypress fashion we created an extension to SystTick.  It does two basic things</p>
<ol>
<li>Lets you pick different clock sources for the SysTick timer</li>
<li>Lets you setup multiple callbacks to make it easier to trigger multiple functions in your system</li>
</ol>
<p>For this example I modified the previous project by commenting out the CMSIS calls.  And I use the Cy_SysTick calls.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">#include "cy_pdl.h"
#include "cycfg.h"
#include &lt;stdio.h&gt;

volatile uint32_t count;
cy_stc_scb_uart_context_t kitprog_context;

#if 0
void SysTick_Handler(void)
{
	count += 1;
}
#endif

void MyHander(void)
{
	count += 1;
}

int main(void)
{
	Cy_SCB_UART_Init(kitprog_HW,&amp;kitprog_config,&amp;kitprog_context);
	Cy_SCB_UART_Enable(kitprog_HW);
    /* Set up internal routing, pins, and clock-to-peripheral connections */
    init_cycfg_all();

    Cy_SysTick_Init ( CY_SYSTICK_CLOCK_SOURCE_CLK_CPU, 100000000/1000); // CPU Freq divide by 1000 makes MS
    Cy_SysTick_SetCallback(0,MyHander); // Slot 0
    Cy_SysTick_Enable();
    
//    SysTick_Config(SystemCoreClock/1000);

    /* enable interrupts */
    __enable_irq();

    for (;;)
    {
    		printf("Test count=%d\n",(int)count);
        Cy_GPIO_Inv(LED_RED_PORT, LED_RED_PIN); /* toggle the pin */
        Cy_SysLib_Delay(1000/*msec*/);
    }
}
</pre>
<p>When you look at this program you might ask where I got the &#8220;100000000/1000&#8243;&#8230;. and if Hassane is reading he will ask WHY DIDN&#8217;T YOU COMMENT IT.   The answer to the first question is that it is the CPU Frequency divided by 1000 to get a millisecond timer.</p>
<p><a href="https://iotexpert.com/?attachment_id=6816" rel="attachment wp-att-6816"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM-703x1024.png" alt="" width="703" height="1024" class="alignnone size-large wp-image-6816" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM-703x1024.png 703w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM-600x874.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM-206x300.png 206w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM-768x1119.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.41.05-AM.png 1072w" sizes="auto, (max-width: 703px) 100vw, 703px" /></a></p>
<p>As to the second question&#8230; the answer is &#8230; &#8220;I just did&#8221; <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>There is probably some MACRO for those values&#8230; but I just don&#8217;t know what they are&#8230; and I suppose that I should go look&#8230; but&#8230;</p>
<p>And finally the &#8220;// slot 0&#8221;  means that it uses the first of 5 slots&#8230; in other words places where you can store a callback.</p>
<p><a href="https://iotexpert.com/?attachment_id=6817" rel="attachment wp-att-6817"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.43.29-AM.png" alt="" width="960" height="126" class="alignnone size-full wp-image-6817" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.43.29-AM.png 960w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.43.29-AM-600x79.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.43.29-AM-300x39.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.43.29-AM-768x101.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></p>
<h1>FreeRTOS usage of SysTick</h1>
<p>The FreeRTOS by default uses the SysTick timer to cause the scheduler to run.  And it does this by using the CMSIS interface&#8230; well because everyone needs to do their own thing, it actually lets you define the function.  Here is a clip out of FreeRTOSConfig.h where it defines the actual function name as xPortSysTickHandler.</p>
<pre class="start-line:180 EnlighterJSRAW" data-enlighter-language="c" ">/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler     SVC_Handler
#define xPortPendSVHandler  PendSV_Handler
#define xPortSysTickHandler SysTick_Handler</pre>
<p>And when you look around (using find) you will find it in the file port.c.</p>
<pre class="start-line:468 lang:c decode:true">void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known. */
	portDISABLE_INTERRUPTS();
	{
		/* Increment the RTOS tick. */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	portENABLE_INTERRUPTS();
}</pre>
<p>And if you look in vTaskStartScheduler you will find that it calls the function vPortSetupTimerInterrupt where it sets up interrupt manually.</p>
<pre class="start-line:655 EnlighterJSRAW" data-enlighter-language="c"">/*
 * Setup the systick timer to generate the tick interrupts at the required
 * frequency.
 */
__attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{
	/* Calculate the constants required to configure the tick interrupt. */
	#if( configUSE_TICKLESS_IDLE == 1 )
	{
		ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
		xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
		ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
	}
	#endif /* configUSE_TICKLESS_IDLE */

	/* Stop and clear the SysTick. */
	portNVIC_SYSTICK_CTRL_REG = 0UL;
	portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

	/* Configure SysTick to interrupt at the requested rate. */
	portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
	portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}</pre>
<p>And what is really cool is that when you look in FreeRTOSConfig.h you can see that it uses the CMSIS macro &#8220;SystemCoreClock&#8221; and that it is configured to have a 1MS callback.</p>
<pre class="start-line:49 EnlighterJSRAW" data-enlighter-language="c" ">#define configCPU_CLOCK_HZ                      SystemCoreClock
#define configTICK_RATE_HZ                      1000u</pre>
<p>So, why did I look at all of that?  Well simple, each time that the SysTick interrupt is called, the FreeRTOS adds 1 to a count&#8230;. which you can get access to by calling &#8220;xTaskGetTickCount&#8221;.  Nice.</p>
<p>I think that is enough background&#8230; so let&#8217;s:</p>
<h1>Make a New Project</h1>
<p>I want to start by creating a copy of the project from the previous article (so that alls yall can see the progression of code changes).  In the previous article I walked you step-by-step through creating and copying a project.  Here is a summary of the step you need to take.  If you want to see the details please look at the <a href="https://iotexpert.com/2019/04/21/cy8ckit-028-eink-mo-better/">last article</a>.</p>
<ol>
<li>Make a new project</li>
<li>Copy design.modus</li>
<li>Add the middleware (FreeRTOS, Segger Core OS NoTouch &amp; Soft FP,Segger BitPlains, Retarget I/O)</li>
<li>Copy all of the files from the source directory</li>
<li>Update the Include paths with the &#8220;eInk Library&#8221; and &#8220;emWin_Config&#8221;</li>
</ol>
<p>After making all of these changes I will have a project in my workspace called &#8220;EHKEinkTiming&#8221;.  I would recommend before you go further that you build and program to make sure that everything is still working.</p>
<h1>Measure the SPI Speed Increase</h1>
<p>All of the action to dump the frame buffer onto the EINK display happens in the function UpdateDisplay in the file eInkTask.c.  In the code below you can see that I ask FreeRTOS what the count is before I dump the display, then what the count is after it is done.</p>
<pre class="start-line:117 EnlighterJSRAW" data-enlighter-language="c"">void UpdateDisplay(cy_eink_update_t updateMethod, bool powerCycle)
{
    /* Copy the EmWin display buffer to imageBuffer*/
    LCD_CopyDisplayBuffer(imageBuffer, CY_EINK_FRAME_SIZE);

    uint32_t startCount = xTaskGetTickCount();
    /* Update the EInk display */
    Cy_EINK_ShowFrame(imageBufferCache, imageBuffer, updateMethod, powerCycle);
    uint32_t endCount = xTaskGetTickCount();
    printf("Update Display Time = %d\n",(int)(endCount - startCount));

    /* Copy the EmWin display buffer to the imageBuffer cache*/
    LCD_CopyDisplayBuffer(imageBufferCache, CY_EINK_FRAME_SIZE);
}</pre>
<p>When I run the updated program I find that it takes about 1.7 seconds to update the screen.</p>
<p><a href="https://iotexpert.com/?attachment_id=6819" rel="attachment wp-att-6819"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM-1024x705.png" alt="" width="1024" height="705" class="alignnone size-large wp-image-6819" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM-1024x705.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM-600x413.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM-300x207.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM-768x529.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.57.43-AM.png 1202w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Then I go back and modify the original program (before the SPI fixes) to see how long it takes&#8230;</p>
<p><a href="https://iotexpert.com/?attachment_id=6820" rel="attachment wp-att-6820"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM-1024x704.png" alt="" width="1024" height="704" class="alignnone size-large wp-image-6820" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM-1024x704.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM-600x413.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM-300x206.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM-768x528.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-11.59.18-AM.png 1192w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And yes if you can do math, which I&#8217;m sure everyone who has read this far can, you will notice that I only sped things up by 65 Milliseconds&#8230; which means you need to call bullshit on my original declaration that it was noticeably faster.  Oh well at least I learned a bunch about the clock system.</p>
<h1>Remove the HW timer &amp; Update the EINK Driver</h1>
<p>OK now that we have the hang of SysTick, it is clear that we don&#8217;t need the hardware timer that we put into the first project, so let&#8217;s get it out of there.  Start by running design.modus and removing the timer.  Just click the checkbox on &#8220;TCPWM[1]&#8230;&#8221; to turn it off.  Then press save.</p>
<p><a href="https://iotexpert.com/?attachment_id=6822" rel="attachment wp-att-6822"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-12.05.15-PM.png" alt="" width="918" height="398" class="alignnone size-full wp-image-6822" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-12.05.15-PM.png 918w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-12.05.15-PM-600x260.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-12.05.15-PM-300x130.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-27-at-12.05.15-PM-768x333.png 768w" sizes="auto, (max-width: 918px) 100vw, 918px" /></a></p>
<p>If you hit compile you will find a whole bunch of errors&#8230; but they are all in four functions inside of cy_eink_psoc_interface.c.   Specifically</p>
<ul>
<li>Cy_EINK_TimerInit</li>
<li><span>Cy_EINK_GetTimeTick</span></li>
<li>Cy_EINK_TimerStop</li>
</ul>
<p>To fix them Ill first create a global static variable called &#8220;timerCount&#8221;</p>
<pre class="start-line:59 EnlighterJSRAW" data-enlighter-language="c" ">static uint32_t timerCount;
</pre>
<p>Then update Cy_EINK_TimerInit to just store the current FreeRTOS timer value in my new global variable.</p>
<pre class="start-line:77 EnlighterJSRAW" data-enlighter-language="c" ">void Cy_EINK_TimerInit(void)
{   
	timerCount = xTaskGetTickCount();
}
</pre>
<p>Next update Cy_EINK_GetTimeTick to return the number of ticks since the timer was initialized.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">uint32_t Cy_EINK_GetTimeTick(void)
{
	    /* Return the current value of time tick */
    return(xTaskGetTickCount()-timerCount);
}
</pre>
<p>Finally, make the TimerStop function do&#8230; well&#8230; nothing.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" ">void Cy_EINK_TimerStop(void)
{
}
</pre>
<p>When I build and program&#8230; my project is off to the races without the hardware timer.</p>
<p>In the next article Ill have a look at the EINK datasheet and driver to look into how it works.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/cy8ckit-028-epd-better-timing/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>CY8CKIT-028-EPD and Modus Toolbox 1.1</title>
		<link>https://iotexpert.com/cy8ckit-028-epd-and-modus-toolbox-1-1/</link>
					<comments>https://iotexpert.com/cy8ckit-028-epd-and-modus-toolbox-1-1/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 15 Apr 2019 21:50:36 +0000</pubDate>
				<category><![CDATA[CY8CKIT-028-EPD]]></category>
		<category><![CDATA[CY8CKIT-062-BLE]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[PSoC 6]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6666</guid>

					<description><![CDATA[Summary One of my very influential readers is working on a project where he wants to use the CY8CKIT-028-EPD.  But, he wants to use Modus Toolbox 1.1 instead of PSoC Creator and he observed, correctly, that Cypress doesn&#8217;t have a MTB code example project for the CY8CKIT-028-EPD.  I knew that we had a working code [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>One of my very influential readers is working on a project where he wants to use the <a href="https://www.cypress.com/documentation/development-kitsboards/e-ink-display-shield-board-cy8ckit-028-epd" target="_blank" rel="noopener noreferrer">CY8CKIT-028-EPD</a>.  But, he wants to use Modus Toolbox 1.1 instead of PSoC Creator and he observed, correctly, that Cypress doesn&#8217;t have a MTB code example project for the CY8CKIT-028-EPD.  I knew that we had a working code example in PSoC Creator (<a href="https://www.cypress.com/documentation/code-examples/ce23727-psoc-6-e-ink-display-interface-emwin-graphics-library" target="_blank" rel="noopener noreferrer">CE223727</a>), so I decided to do a port to MTB1.1.  This turned out to be a bit of an adventure which required me to dig out a logic analyzer to solve self inflicted problems.  Here is a picture I took while sorting it out.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/img_0408/" rel="attachment wp-att-6668"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6668 size-large" srcset="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-scaled-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0408-e1555270252695-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>There are a few things in the PSoC Creator example code which I didn&#8217;t really like, so, for the final solution, I would like it to be</p>
<ul>
<li>In Modus Toolbox 1.1</li>
<li>Using FreeRTOS</li>
<li>Using the Segger emWin graphics library</li>
<li>Getting the best response time</li>
<li>Using DMA to drive the display</li>
</ul>
<p>For this article I will go through these steps:</p>
<ol>
<li>Build CE223727 EmWin_Eink_Display in PSoC Creator</li>
<li>Explain the PSoC Creator Project</li>
<li>Create a new MTB Project &amp; add the FreeRTOS, Segger emWin and stdio middleware</li>
<li>Configure the device for the correct pins, clocks and peripherals</li>
<li>Setup FreeRTOS and Standard I/O</li>
<li>Copy the driver files into the MTB project from the PSoC Creator workspace</li>
<li>Port the drivers and eInkTask to work in MTB</li>
<li>Program and Test</li>
<li>(Part 2) Update the driver to remove the hardware timer</li>
<li>(Part 2) Update the example to remove polled switch and use a semaphore</li>
<li>(Part 2) Update the driver to use DMA</li>
<li>(Part 2) Explain how the EINK EPD Display Works</li>
</ol>
<p>If you lack patience and you just want a working project, you can download it from the <a href="https://github.com/iotexpert/eink-emwin-mtb1-1" target="_blank" rel="noopener noreferrer">IoT Expert GitHub</a> site. git@github.com:iotexpert/eink-emwin-mtb1-1.git</p>
<h1>First build CE223727 EmWin_Eink_Display in PSoC Creator</h1>
<p>Start by finding the code example project for the Eink Display.  In PSoC Creator on the File-&gt;Code Example menu you will be able to pick out the code example.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-53-44-pm/" rel="attachment wp-att-6679"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.53.44-PM.png" alt="" width="242" height="163" class="alignnone size-large wp-image-6679" /></a></p>
<p>There are a bunch of code examples, so the easiest way to find them is the filter based on &#8220;emwin&#8221;.  I did this because I knew we had used the Segger emWin Graphics library.  Notice in the picture below there are two emWin examples.  One with a &#8220;world&#8221; beside it and one without.  The world symbol means that it is on the internet and you will need to download it.  You can do that by clicking the world button.  Probably, you will find that your CE223727 EmWin_EInk_Display will have a world beside it and you will need to download it before you can make the project.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-53-26-pm/" rel="attachment wp-att-6680"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.53.26-PM.png" alt="" width="626" height="478" class="alignnone size-large wp-image-6680" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.53.26-PM.png 626w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.53.26-PM-600x458.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.53.26-PM-300x229.png 300w" sizes="auto, (max-width: 626px) 100vw, 626px" /></a></p>
<p>Once you click create project it will ask you about the project.  Just click &#8220;next&#8221;</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-54-18-pm/" rel="attachment wp-att-6678"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.18-PM.png" alt="" width="626" height="471" class="alignnone size-large wp-image-6678" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.18-PM.png 626w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.18-PM-600x451.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.18-PM-300x226.png 300w" sizes="auto, (max-width: 626px) 100vw, 626px" /></a></p>
<p>Then give your project (and workspace) a name.  I called the workspace &#8220;EPDExample&#8221; and the project &#8220;CE22&#8230;.&#8221;</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-54-40-pm/" rel="attachment wp-att-6677"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.40-PM.png" alt="" width="626" height="466" class="alignnone size-large wp-image-6677" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.40-PM.png 626w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.40-PM-600x447.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.54.40-PM-300x223.png 300w" sizes="auto, (max-width: 626px) 100vw, 626px" /></a></p>
<p>After all of that is done you will have a schematic (and all of the other stuff required for the project).</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-55-50-pm/" rel="attachment wp-att-6675"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM-1024x791.png" alt="" width="1024" height="791" class="alignnone size-large wp-image-6675" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM-1024x791.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM-600x464.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM-300x232.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM-768x593.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.50-PM.png 1126w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>When you click the program button it will ask you which MCU target to program (pick either, it doesnt matter)</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-55-28-pm/" rel="attachment wp-att-6676"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.28-PM.png" alt="" width="557" height="394" class="alignnone size-large wp-image-6676" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.28-PM.png 557w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.55.28-PM-300x212.png 300w" sizes="auto, (max-width: 557px) 100vw, 557px" /></a></p>
<p>After a while, your console window should look like this.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-4-59-13-pm/" rel="attachment wp-att-6681"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM-1024x174.png" alt="" width="1024" height="174" class="alignnone size-large wp-image-6681" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM-1024x174.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM-600x102.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM-300x51.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM-768x130.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-4.59.13-PM.png 1198w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And you development kit should do its thing.</p>
<h1><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/img_0429/" rel="attachment wp-att-6682"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0429-1024x632.jpg" alt="" width="1024" height="632" class="alignnone size-large wp-image-6682" srcset="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0429-1024x632.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0429-600x371.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0429-300x185.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0429-768x474.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></h1>
<h1>Explain the PSoC Creator Project</h1>
<p>Now, lets have a look at the project.  Starting on the upper left hand part of the schematic you find that the interface to the EPD is via a SPI.  The SPI slave select is controlled with the Pervasive driver firmware rather than letting the SPI block directly control it.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-12-52-pm/" rel="attachment wp-att-6688"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.12.52-PM.png" alt="" width="436" height="232" class="alignnone size-full wp-image-6688" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.12.52-PM.png 436w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.12.52-PM-300x160.png 300w" sizes="auto, (max-width: 436px) 100vw, 436px" /></a></p>
<p>The SPI is configured to be 16 megabits per second with CPHA=0 and CPOL=0.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-09-40-pm/" rel="attachment wp-att-6686"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.40-PM.png" alt="" width="795" height="892" class="alignnone size-large wp-image-6686" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.40-PM.png 795w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.40-PM-600x673.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.40-PM-267x300.png 267w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.40-PM-768x862.png 768w" sizes="auto, (max-width: 795px) 100vw, 795px" /></a></p>
<p>I didn&#8217;t notice this at first, but in the picture above you can see that the actual speed of the SPI is 8.33 mbs.  That isn&#8217;t 16mbs for sure.  But why the gap?  The first thing to know is that in order for the SPI block to work correctly the input clock must be set at the desired datarate times the oversample.  What is oversample?  That is a scheme to get rid of glitchy-ness in the input signal.  In this case it will take 6 input samples to determine if the input is a 1 or a 0.  (median filter I think).  With this configuration the input clock to the SCB needs to be 16mbs * 6 = 96mhz.</p>
<p>But what is the input clock frequency?  If you click on the dwr-&gt;clocks you will see this screen which shows that the input clock is 50Mhz (the last line highlighted in blue).  Further more you can see that the source clock for the SCB is &#8220;Clk_Peri&#8221;.  When you divide 50mhz source clock rate by 6 oversample you will find that the actual bitrate is 8.33kbs.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-15-57-pm/" rel="attachment wp-att-6691"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM.png" alt="" width="786" height="777" class="alignnone size-large wp-image-6691" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM.png 786w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM-100x100.png 100w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM-600x593.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM-300x297.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.15.57-PM-768x759.png 768w" sizes="auto, (max-width: 786px) 100vw, 786px" /></a></p>
<p>But where does the 50mhz come from?  Well, the clock system is driven by the &#8220;IMO&#8221;.  IMO stands for internal main oscillator and it is a trimmed RC oscillator built into the chip. (thanks Tim).  This oscillator runs into an FLL which up converts it to 100MHz.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-17-08-pm/" rel="attachment wp-att-6689"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.17.08-PM.png" alt="" width="768" height="554" class="alignnone size-full wp-image-6689" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.17.08-PM.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.17.08-PM-600x433.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.17.08-PM-300x216.png 300w" sizes="auto, (max-width: 768px) 100vw, 768px" /></a></p>
<p>That signal is then run into the &#8220;Clk_Peri&#8221; divider which divides it by two to yield a clock of 50MHz.  Which is not all that close to 96MHz&#8230; and means that our SPI runs at the wrong speed.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-16-57-pm/" rel="attachment wp-att-6690"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.16.57-PM.png" alt="" width="779" height="445" class="alignnone size-large wp-image-6690" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.16.57-PM.png 779w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.16.57-PM-600x343.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.16.57-PM-300x171.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.16.57-PM-768x439.png 768w" sizes="auto, (max-width: 779px) 100vw, 779px" /></a></p>
<p>But what does the EPD driver chip actually want?  You can find the documentation for this EPD on the Pervasive <a href="http://www.pervasivedisplays.com/products/271" target="_blank" rel="noopener noreferrer">website</a>.  That web page also has a link to the Product Specification <a href="http://www.pervasivedisplays.com/LiteratureRetrieve.aspx?ID=238025">2.7&#8243; TFT EPD Panel (E2271CS021) Rev.01</a> as well as the driver chip <a href="http://www.pervasivedisplays.com/_literature_220873/COG_Driver_Interface_Timing_for_small_size_G2_V231">COG Driver Interface Timing for small size G2 V231</a></p>
<p>When you look in the timing document you will find that the actual chip can take up to a 20Mhz input clock.  This means that our code example actually updates the screen at 42% (8.33/20) of what it could.  That gives us a chance to make things faster&#8230; which I will do after the port to MTB.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-25-08-pm/" rel="attachment wp-att-6692"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.25.08-PM.png" alt="" width="743" height="207" class="alignnone size-full wp-image-6692" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.25.08-PM.png 743w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.25.08-PM-600x167.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.25.08-PM-300x84.png 300w" sizes="auto, (max-width: 743px) 100vw, 743px" /></a></p>
<p>The next sectin of the schematic has a TCPWM that is configured as a timer.  This has an input clock of 2kHz.</p>
<p>&nbsp;</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-10-00-pm/" rel="attachment wp-att-6685"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.00-PM.png" alt="" width="445" height="255" class="alignnone size-large wp-image-6685" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.00-PM.png 445w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.00-PM-300x172.png 300w" sizes="auto, (max-width: 445px) 100vw, 445px" /></a></p>
<p>And is setup to divide by 2 which will yield a counter that updates every 1ms.  The author of this code example used the TCPWM to time operations inside of the driver (which I will also replace with something better)</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-10-09-pm/" rel="attachment wp-att-6684"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.09-PM.png" alt="" width="626" height="476" class="alignnone size-full wp-image-6684" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.09-PM.png 626w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.09-PM-600x456.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.10.09-PM-300x228.png 300w" sizes="auto, (max-width: 626px) 100vw, 626px" /></a></p>
<p>Lastly there are some GPIOs that control various control pins on the display.  I don&#8217;t really know what all of the pins do, but will sort it out in the next article.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-47-16-pm/" rel="attachment wp-att-6694"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.47.16-PM.png" alt="" width="499" height="639" class="alignnone size-full wp-image-6694" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.47.16-PM.png 499w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.47.16-PM-234x300.png 234w" sizes="auto, (max-width: 499px) 100vw, 499px" /></a></p>
<p>And all of the pins are assigned like this:</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-09-03-pm/" rel="attachment wp-att-6687"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM.png" alt="" width="670" height="297" class="alignnone size-large wp-image-6687" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM.png 670w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM-600x266.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.09.03-PM-300x133.png 300w" sizes="auto, (max-width: 670px) 100vw, 670px" /></a></p>
<h1>Create a new MTB project &amp; Add the Middleware</h1>
<p>It is time to start the project in MTB.  Start up Modus Toolbox 1.1 and select File-&gt;New-&gt;ModusToobox IDE Application    <a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-8-57-36-am/" rel="attachment wp-att-6701"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM-1024x173.png" alt="" width="1024" height="173" class="alignnone size-large wp-image-6701" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM-1024x173.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM-600x101.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM-300x51.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM-768x129.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.57.36-AM.png 1614w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Then select the CY8CKIT-062-BLE Development Kit.  This kit comes with the CY8CKIT-028-EPD EINK Shield that you can see in the pictures above.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-8-58-04-am/" rel="attachment wp-att-6700"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM-1024x489.png" alt="" width="1024" height="489" class="alignnone size-large wp-image-6700" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM-1024x489.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM-600x287.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM-300x143.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM-768x367.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.04-AM.png 2030w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>I decide to call my project &#8220;EHKEink&#8221; and I derive my project from the &#8220;EmptyPSoC6App&#8221; template.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-8-58-32-am/" rel="attachment wp-att-6699"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM-1024x490.png" alt="" width="1024" height="490" class="alignnone size-large wp-image-6699" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM-1024x490.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM-600x287.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM-300x144.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM-768x367.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.32-AM.png 2032w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Once that is done, Let it rip.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-8-58-51-am/" rel="attachment wp-att-6698"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM-1024x718.png" alt="" width="1024" height="718" class="alignnone size-large wp-image-6698" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM-1024x718.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM-600x421.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM-300x210.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM-768x538.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-8.58.51-AM.png 1224w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>And you should end up with a screen that looks like this. On the left in the workspace explorer you see the main app project.  In the middle you see the readme file which explains how this project is configured.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-01-13-am-2/" rel="attachment wp-att-6703"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.01.13-AM-1-1024x626.png" alt="" width="1024" height="626" class="alignnone size-large wp-image-6703" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.01.13-AM-1-1024x626.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.01.13-AM-1-600x367.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.01.13-AM-1-300x183.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.01.13-AM-1-768x469.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The next step is to add the &#8220;Middleware&#8221; that we need to make this project work.  You can do this by clicking the select Middleware button from the ModusToolbox quick panel.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-13-02-am/" rel="attachment wp-att-6704"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.13.02-AM.png" alt="" width="708" height="852" class="alignnone size-full wp-image-6704" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.13.02-AM.png 708w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.13.02-AM-600x722.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.13.02-AM-249x300.png 249w" sizes="auto, (max-width: 708px) 100vw, 708px" /></a></p>
<p>For this project we need</p>
<ul>
<li>FreeRTOS</li>
<li>Retarget I/O</li>
<li>Segger emWin Core, OS, no Touch, Soft FP</li>
<li>Segger emWin display driver BitPlains</li>
</ul>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-18-52-am/" rel="attachment wp-att-6708"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM-1024x911.png" alt="" width="1024" height="911" class="alignnone size-large wp-image-6708" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM-1024x911.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM-600x534.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM-300x267.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM-768x683.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.18.52-AM.png 1972w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The middleware selector will bring in all of the drivers you selected into your project.  You can see that it also adds the FreeRTOS configuration file &#8220;FreeRTOSConfig.h&#8221; as well as &#8220;stdio_user.c&#8221; etc.  These files endup in the source folder and are for you to edit.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-19-50-am/" rel="attachment wp-att-6707"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.19.50-AM.png" alt="" width="718" height="788" class="alignnone size-full wp-image-6707" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.19.50-AM.png 718w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.19.50-AM-600x658.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.19.50-AM-273x300.png 273w" sizes="auto, (max-width: 718px) 100vw, 718px" /></a></p>
<p>While I was working on this, I found a bug in the emWin middleware, specifically the the configuration files for BitPlains get included twice.  To fix this you need to change the project properties and remove the path to &#8220;..components/psoc6mw/emWin/code/drivers/BitPlains/config&#8221;.  To do this, select the project in the workspace explorer then right click and select properties.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-22-04-am/" rel="attachment wp-att-6710"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM-543x1024.png" alt="" width="543" height="1024" class="alignnone size-large wp-image-6710" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM-543x1024.png 543w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM-600x1131.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM-159x300.png 159w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM-768x1447.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.04-AM.png 916w" sizes="auto, (max-width: 543px) 100vw, 543px" /></a></p>
<p>Then select &#8220;C/C++ General &#8211;&gt; Paths and Symbols&#8221;.  Select the &#8220;&#8230;BitPlains/config&#8221; path and click &#8220;Delete&#8221;</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-22-43-am/" rel="attachment wp-att-6709"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.43-AM-1024x541.png" alt="" width="1024" height="541" class="alignnone size-large wp-image-6709" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.43-AM-1024x541.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.43-AM-600x317.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.43-AM-300x158.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.22.43-AM-768x405.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Configure the device in MTB</h1>
<p>Modus Toolbox does not have a &#8220;schematic&#8221; or a &#8220;dwr&#8221; like PSoC Creator.  In order to achieve the same functionality we built the &#8220;Configurator&#8221;.  This tool will let you setup all of the peripherals in your project.  To run it select &#8220;Configure Device&#8221; in the MTB Quick Panel.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-29-54-am/" rel="attachment wp-att-6712"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.29.54-AM.png" alt="" width="714" height="938" class="alignnone size-full wp-image-6712" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.29.54-AM.png 714w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.29.54-AM-600x788.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.29.54-AM-228x300.png 228w" sizes="auto, (max-width: 714px) 100vw, 714px" /></a></p>
<p>Remember from the PSoC Creator Schematic we need to have:</p>
<ul>
<li>A bunch of pins</li>
<li>A SPI</li>
<li>A Timer</li>
<li>Plus I want a UART to connect to standard I/O.</li>
</ul>
<p>First, click on the &#8220;Pins&#8221; tab.  This lets you set all of the configuration information for each of the pins on the chip.  I will go one by one enabling the pins and setting them as digital inputs or output.  I am going to give all of the pins that exact same names that they had in the PSoC Creator Project because I know the author of that project used PDL.  When you give a pin a name in the configurator it will generate #defines or c structures based on the name.  This will make the source code the original PSoC Creator author wrote almost exactly compatible with MTB.</p>
<p>Here is an example of the first output pin which is P0[2] and is named CY_EINK_DispIoEn.  For the output pins you need to do four things.</p>
<ol>
<li>Enable the checkbox next to the pin name. (in this case P0[2])</li>
<li>Give the pin a name (CY_EINK_DispIoEn)</li>
<li>Set the drive mode (Strong Drive, Input buffer off)</li>
<li>Set the initial state of the pin (High (1))</li>
</ol>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-48-55-am/" rel="attachment wp-att-6716"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM-1024x889.png" alt="" width="1024" height="889" class="alignnone size-large wp-image-6716" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM-1024x889.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM-600x521.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM-300x260.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM-768x667.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.48.55-AM.png 1726w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now, you need to go one by one turning on all of the output pins (Im not showing you screen shots of all of them)</p>
<p>There are two input pins for this project SW2 P0[4] and CY_EINK_DispBusy P5[3].  For these pins I will:</p>
<ol>
<li>Enable the pin checkbox</li>
<li>Give the pin a name (in this case SW2)</li>
<li>Resistive Pull-Up, Input buffer on.  Note for P5[3] the pullup resistor is not needed</li>
</ol>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-52-01-am/" rel="attachment wp-att-6718"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM-1024x894.png" alt="" width="1024" height="894" class="alignnone size-large wp-image-6718" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM-1024x894.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM-600x524.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM-300x262.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM-768x670.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.52.01-AM.png 1698w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now that the digital pins are configured, you can setup the STDIO Uart.  This will be used to send debugging messages to the console Uart which is attached to your computer via a USB&lt;-&gt;UART bridge in KitProg 3.</p>
<p>Start by enabling SCB5 and giving it the name &#8220;UART&#8221;.  Make sure that the baud rate is set to 115200 and the rest to 8n1<a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-57-26-am/" rel="attachment wp-att-6720"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM-820x1024.png" alt="" width="820" height="1024" class="alignnone size-large wp-image-6720" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM-820x1024.png 820w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM-600x749.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM-240x300.png 240w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM-768x959.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.57.26-AM.png 1190w" sizes="auto, (max-width: 820px) 100vw, 820px" /></a></p>
<p>Scroll down the window and pick out the RX and TX Pins plus the clock (any of the 8-bit clock dividers will do.  In this case I chose Divider 0)</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-9-58-51-am/" rel="attachment wp-att-6721"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM-1024x657.png" alt="" width="1024" height="657" class="alignnone size-large wp-image-6721" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM-1024x657.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM-600x385.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM-300x192.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM-768x493.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-9.58.51-AM.png 1244w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Now, you need to setup the SPI.  To do this turn on SCB 6, set it to SPI, give it the name &#8220;CY_EINK_SPIM&#8221;, set it to &#8220;Master&#8221;, fix the data rate to 1000<a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-10-01-18-am/" rel="attachment wp-att-6722"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM-1024x993.png" alt="" width="1024" height="993" class="alignnone size-large wp-image-6722" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM-1024x993.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM-600x582.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM-300x291.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM-768x745.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.01.18-AM.png 1524w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Then scroll down to the &#8220;Connections&#8221; section and assign the pins</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-3-48-22-pm/" rel="attachment wp-att-6744"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM-1024x588.png" alt="" width="1024" height="588" class="alignnone size-large wp-image-6744" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM-1024x588.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM-600x345.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM-300x172.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM-768x441.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.48.22-PM.png 1146w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The last bit of hardware we need is a timer with a 1000kHz input clock, in other words a millisecond timer.  To do this start by enabling TCPWM[1] 16-bit counter.  Call it &#8220;CY_EINK_Timer&#8221; which was the same name as the PSoC Creator project.  Then setup</p>
<ul>
<li>As a &#8220;Timer Counter&#8221;.</li>
<li>One shot</li>
<li>Up count</li>
<li>Period is 65535 (aka the max)</li>
<li>And pick &#8220;Clock signal&#8221; as 16 bit Divider</li>
</ul>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-12-26-51-pm/" rel="attachment wp-att-6736"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM-1024x858.png" alt="" width="1024" height="858" class="alignnone size-large wp-image-6736" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM-1024x858.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM-600x503.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM-300x251.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM-768x644.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.26.51-PM.png 1592w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Given that we want it to count milliseconds and the input has a 128 bit pre-divider&#8230; we need for the input clock to be setup to 128khz.  Click on &#8220;Peripheral clocks&#8221; then select &#8220;16 Bit Divider 0&#8221;.  Notice that the input frequency is 72Mhz and we need 128Khz&#8230; to get this a divider of 562 is required.  72mhz/128khz = 562</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-12-35-10-pm/" rel="attachment wp-att-6737"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM-1024x901.png" alt="" width="1024" height="901" class="alignnone size-large wp-image-6737" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM-1024x901.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM-600x528.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM-300x264.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM-768x676.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-12.35.10-PM.png 1412w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Setup FreeRTOS and Standard I/O</h1>
<p>The next step is to setup the &#8220;plumbing&#8221;.  In this projet we are using FreeRTOS and Standard I/O. To configure FreeRTOS just edit the &#8220;FreeRTOSConfig.h&#8221; and remove the &#8220;warning&#8221;</p>
<pre class="start-line:45 EnlighterJSRAW" data-enlighter-language="c"">#warning This is a template. Modify it according to your project and remove this line. 
</pre>
<p>Enable mutexes on line 57</p>
<pre class="start-line:57 EnlighterJSRAW" data-enlighter-language="c"">#define configUSE_MUTEXES                       1
</pre>
<p>Make the heap bigger on line 70</p>
<pre class="start-line:70 EnlighterJSRAW" data-enlighter-language="c"">#define configTOTAL_HEAP_SIZE                   1024*48
</pre>
<p>Change the memory scheme to 4 on line 194</p>
<pre class="start-line:194 EnlighterJSRAW" data-enlighter-language="c"">#define configHEAP_ALLOCATION_SCHEME                (HEAP_ALLOCATION_TYPE4)
</pre>
<p>To enable the UART to be used for Standard I/O, edit &#8220;stdio_user.h&#8221; and add the includes for &#8220;cycfg.h&#8221;.  Then update the output and input Uart to be &#8220;UART_HW&#8221; (which is the name you gave it in the configurator)</p>
<pre class="start-line:172 EnlighterJSRAW" data-enlighter-language="c"">#include "cycfg.h"
/* Must remain uncommented to use this utility */
#define IO_STDOUT_ENABLE
#define IO_STDIN_ENABLE
#define IO_STDOUT_UART      UART_HW
#define IO_STDIN_UART       UART_HW
</pre>
<p>Now make a few edits to main.c to</p>
<ul>
<li>Add includes for the configuration, rtos and standard i/o</li>
<li>Create a context for the UART</li>
<li>Create a blinking LED Task</li>
<li>In main start the UART and start the blinking LED task.</li>
</ul>
<pre class="start-line:27 EnlighterJSRAW" data-enlighter-language="c"">#include "cy_device_headers.h"
#include "cycfg.h"
#include "FreeRTOS.h"
#include "task.h"
#include &lt;stdio.h&gt;

cy_stc_scb_uart_context_t UART_context;

void blinkTask(void *arg)
{
	(void)arg;

    for(;;)
    {
    		vTaskDelay(500);
    		Cy_GPIO_Inv(LED_RED_PORT,LED_RED_PIN);
    		printf("blink\n");
    }
}
int main(void)
{
    init_cycfg_all();
    __enable_irq();

    Cy_SCB_UART_Init(UART_HW,&amp;UART_config,&amp;UART_context);
	Cy_SCB_UART_Enable(UART_HW);

  	xTaskCreate( blinkTask,"blinkTask", configMINIMAL_STACK_SIZE,  0,  1, 0  );
  	vTaskStartScheduler();
  	while(1);// Will never get here
}
</pre>
<p>As I edited the code I notice that it can&#8217;t find &#8220;LED_RED&#8221; which made me realize that I forgot to add the LED_RED attached to P0[3] in the configuration.  So, I go back and update P0[3] to be LED_RED as strong drive digital output.</p>
<p>Finally just to make sure that it is all working lets program the kit.  When I press &#8220;EHKEink Program&#8221; form the quickpanel&#8230;<a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-10-45-20-am/" rel="attachment wp-att-6725"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.45.20-AM.png" alt="" width="710" height="880" class="alignnone size-full wp-image-6725" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.45.20-AM.png 710w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.45.20-AM-600x744.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.45.20-AM-242x300.png 242w" sizes="auto, (max-width: 710px) 100vw, 710px" /></a></p>
<p>I get this message in the console.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-10-46-38-am/" rel="attachment wp-att-6726"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM-1024x493.png" alt="" width="1024" height="493" class="alignnone size-large wp-image-6726" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM-1024x493.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM-600x289.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM-300x145.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM-768x370.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.46.38-AM.png 1100w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>But how can that be?  I have my kit plugged in?  In order to program your kit using Modus you need &#8220;KitProg3&#8221;.  PSoC Creator can program you kit with KitProg3 only if it is in the CMSIS-DAP HID mode.  To switch you development kit to KitProg3, you can use the program &#8220;fw-loader&#8221; which comes with MTB.  You can see what firmware you have by running &#8220;fw-loader &#8211;device-list&#8221;.  To change to KitProg 2 run &#8220;fw-loader &#8211;update-kp2&#8221; and to update to KitProg3 run &#8220;fw-loader &#8211;update-kp3&#8221;</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-14-at-5-35-26-pm/" rel="attachment wp-att-6693"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.35.26-PM.png" alt="" width="980" height="523" class="alignnone size-full wp-image-6693" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.35.26-PM.png 980w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.35.26-PM-600x320.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.35.26-PM-300x160.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-14-at-5.35.26-PM-768x410.png 768w" sizes="auto, (max-width: 980px) 100vw, 980px" /></a></p>
<p>Now when i program I get both the LED blinking and the console printing blink.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-10-37-24-am/" rel="attachment wp-att-6728"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM-1024x700.png" alt="" width="1024" height="700" class="alignnone size-large wp-image-6728" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM-1024x700.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM-600x410.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM-300x205.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM-768x525.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.37.24-AM.png 1190w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Copy the files into the MTB project</h1>
<p>Next, I want to bring over the drivers from the PSoC Creator project.  They reside in folder called &#8220;eInk Library&#8221; inside of the PSoC Creator project.  You can copy them by navigating to the PSoC Creator workspace, then typing ctrl-c in the File Explorer, then clicking the &#8220;Source&#8221; directory in your Eclipse WorkSpace explorer and typing ctrl-v<a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-10-56-36-am/" rel="attachment wp-att-6730"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.56.36-AM-1024x596.png" alt="" width="1024" height="596" class="alignnone size-large wp-image-6730" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.56.36-AM-1024x596.png 1024w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.56.36-AM-600x349.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.56.36-AM-300x174.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-10.56.36-AM-768x447.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>You will also need the four files &#8220;GUIConf.c&#8221;, &#8220;GUIConf.h&#8221;, &#8220;LCDConf.h&#8221; and &#8220;LCDConf.c&#8221;.  Copy and paste them into the emWin_config directory.</p>
<p>For this project I am going to use the code that existed in &#8220;main.c&#8221; from the original PSoC Creator project.  But I want it to be a task (and a few other changes).  To facilitate things, I will copy it as well. Then rename it to eInkTask.c.  And finally, the file &#8220;Cypress Logo Full Color_png1bpp.c&#8221; needs to be copied as well.</p>
<p>After all of those copies you should have your project looking something like this:</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-3-58-04-pm/" rel="attachment wp-att-6745"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.58.04-PM.png" alt="" width="710" height="820" class="alignnone size-full wp-image-6745" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.58.04-PM.png 710w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.58.04-PM-600x693.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-3.58.04-PM-260x300.png 260w" sizes="auto, (max-width: 710px) 100vw, 710px" /></a></p>
<h1>Port the Drivers and eInkTask</h1>
<p>Now we need to fix all of the driver code.  Big picture you will need to take the following actions.</p>
<ul>
<li>Update the Project settings to include the new folders (emWin_config and emWin Library)</li>
<li>Replace the PSoC Creator #include &lt;project.h&gt; with MTB #include &#8220;cycfg.h&#8221;</li>
<li>Update the files to have #include &#8220;FreeRTOS.h&#8221; and &#8220;task.h&#8221; where appropriate</li>
<li>Replace all of the CyDelay&#8217;s with vTaskDelays</li>
<li>Fix the old PSoC Creator component calls for the timer with PDL calls</li>
</ul>
<p>First go to the project settings (remember, click on the project then select properties).  Then pick &#8220;C/C++ Build Settings&#8221; then &#8220;GNU ARM Cross C Compiler&#8221; and &#8220;includes&#8221;  Press the little green &#8220;+&#8221; to add the new directories</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-11-29-00-am/" rel="attachment wp-att-6732"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM-1003x1024.png" alt="" width="1003" height="1024" class="alignnone size-large wp-image-6732" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM-1003x1024.png 1003w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM-600x612.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM-294x300.png 294w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM-768x784.png 768w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.29.00-AM.png 1546w" sizes="auto, (max-width: 1003px) 100vw, 1003px" /></a></p>
<p>You can select both directories at once.</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/screen-shot-2019-04-15-at-11-28-31-am/" rel="attachment wp-att-6733"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.28.31-AM.png" alt="" width="794" height="782" class="alignnone size-large wp-image-6733" srcset="https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.28.31-AM.png 794w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.28.31-AM-600x591.png 600w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.28.31-AM-300x295.png 300w, https://iotexpert.com/wp-content/uploads/2019/04/Screen-Shot-2019-04-15-at-11.28.31-AM-768x756.png 768w" sizes="auto, (max-width: 794px) 100vw, 794px" /></a></p>
<p>Next edit  <strong>eInkTask.c</strong></p>
<p>Update #include &#8220;project.h&#8221; to be #include &#8220;cycfg.h&#8221; on line 59.  Add &#8220;FreeRTOS.h&#8221; and &#8220;task.h&#8221; to the includes.</p>
<pre class="start-line:59 EnlighterJSRAW" data-enlighter-language="c"">#include "cycfg.h"
#include "GUI.h"
#include "pervasive_eink_hardware_driver.h"
#include "cy_eink_library.h"
#include "LCDConf.h"
#include "FreeRTOS.h"
#include "task.h"
#include &lt;stdio.h&gt;</pre>
<p>Find and replace &#8220;CyDelay&#8221; with &#8220;vTaskDelay&#8221;</p>
<p>Update the PSoC Creator component call  _Read with the pdl calls Cy_GPIO_Read on line 661</p>
<pre class="start-line:661 EnlighterJSRAW" data-enlighter-language="c"">void WaitforSwitchPressAndRelease(void)
{
    /* Wait for SW2 to be pressed */
    while(Cy_GPIO_Read(SW2_PORT,SW2_PIN) != 0);
    
    /* Wait for SW2 to be released */
    while(Cy_GPIO_Read(SW2_PORT,SW2_PIN) == 0);
}</pre>
<p>Update the &#8220;int main(void)&#8221; to be &#8220;void eInkTask(void *arg)&#8221; on line 687</p>
<pre class="start-line:687 EnlighterJSRAW" data-enlighter-language="c" ">void eInkTask(void *arg)
{
	(void)arg;</pre>
<p>Remove &#8221; __enable_irq(); /* Enable global interrupts. */&#8221; from the old main on line 695.</p>
<p>In the file <strong>cy_eink_psoc_interface.h</strong></p>
<p>Update the #include &lt;project.h&gt; to be #include &#8220;cycfg.h&#8221; on line 59.</p>
<p>In the file <strong>cy_eink_psoc_interface.c</strong></p>
<p>Create a context for the SPIM by adding on line 58:</p>
<pre class="start-line:58 EnlighterJSRAW" data-enlighter-language="c" ">cy_stc_scb_spi_context_t CY_EINK_SPIM_context;
</pre>
<p>The three timer functions in this file use the old PSoC Creator component timer interface APIs rather than the PDL interface.  So you will need to change Cy_EINK_TimerInit, Cy_EINK_GetTimeTick and Cy_EINK_TimerStop to use PDL.</p>
<p>Here is Cy_EINK_TimerInit</p>
<pre class="start-line:76 EnlighterJSRAW" data-enlighter-language="c" ">void Cy_EINK_TimerInit(void)
{   
    /* Clear the counter value and the counter variable */
    //CY_EINK_Timer_SetCounter(0);

    Cy_TCPWM_Counter_Init (CY_EINK_Timer_HW, CY_EINK_Timer_NUM, &amp;CY_EINK_Timer_config);
    Cy_TCPWM_Counter_SetCounter	(	CY_EINK_Timer_HW, CY_EINK_Timer_NUM,0);
    
    Cy_TCPWM_Enable_Multiple(	CY_EINK_Timer_HW,CY_EINK_Timer_MASK);
    /* Initialize the Timer */
    //CY_EINK_Timer_Start();
    Cy_TCPWM_TriggerStart	(	CY_EINK_Timer_HW,CY_EINK_Timer_MASK);
}
</pre>
<p>And Cy_EINK_GetTimeTick</p>
<pre class="start-line:106 EnlighterJSRAW" data-enlighter-language="c"">uint32_t Cy_EINK_GetTimeTick(void)
{
    /* Variable used to store the time tick */
    uint32_t timingCount;
    
    /* Read the current time tick from the E-INK Timer */
    //timingCount = CY_EINK_Timer_GetCounter();
    timingCount = Cy_TCPWM_Counter_GetCounter	(CY_EINK_Timer_HW, CY_EINK_Timer_NUM);


    /* Return the current value of time tick */
    return(timingCount);
}</pre>
<p>And Cy_EINK_TimerStop</p>
<pre class="start-line:136 EnlighterJSRAW" data-enlighter-language="c"">void Cy_EINK_TimerStop(void)
{
    /* Stop the E-INK Timer */
    //CY_EINK_Timer_Disable();
	Cy_TCPWM_Counter_Disable(CY_EINK_Timer_HW, CY_EINK_Timer_NUM);

}</pre>
<p>In  the file LCDConf.h change the include to stdint.h and make the type uint8_t instead of uint8</p>
<pre class="start-line:48 EnlighterJSRAW" data-enlighter-language="c"">#include  &lt;stdint.h&gt;
    
void LCD_CopyDisplayBuffer(uint8_t * destination, int count);</pre>
<p>In the file <strong>LCDConf.c</strong> remove the #include &#8220;<span>syslib</span>/cy_syslib.h&#8221; (I have no idea why it is/was there) and then add &#8220;<span>#include</span><span> </span>&lt;stdint.h&gt;&#8221;  On line 219 change &#8220;uint8&#8221; to be &#8220;uint8_t&#8221;</p>
<pre class="start-line:219 EnlighterJSRAW" data-enlighter-language="c" ">void LCD_CopyDisplayBuffer(uint8_t * destination, int count)
</pre>
<p>In the file <strong>cy_eink_fonts.h</strong> change the &#8220;#include &lt;project.h&gt;&#8221; to be</p>
<pre class="start-line:56 EnlighterJSRAW" data-enlighter-language="c" ">#include &lt;stdint.h&gt;
#include &lt;stdbool.h&gt;</pre>
<p>In <strong>main.c</strong> add an external reference to the eInkTask on line 36 (yes this is really ugly Alan)</p>
<pre class="start-line:36 EnlighterJSRAW" data-enlighter-language="c" ">extern void eInkTask(void *);
</pre>
<p>And start the eInkTask on line 58.  Notice that I put in 10K for the stacksize&#8230; but I dont actually know how much it takes.</p>
<pre class="start-line:58 EnlighterJSRAW" data-enlighter-language="c"">  	xTaskCreate( eInkTask,"eInkTask", 1024*10,  0,  1, 0  );
</pre>
<h1>Program &amp; Test the MTB Project</h1>
<p>When you program the development kit you should have</p>
<ol>
<li>A blinking RED LED</li>
<li>The ability to scroll through a bunch of screens using the SW2 button.</li>
</ol>
<p>Here is a picture</p>
<p><a href="https://iotexpert.com/2019/04/15/cy8ckit-028-epd-and-modus-toolbox-1-1/img_0433/" rel="attachment wp-att-6747"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0433-1024x608.jpg" alt="" width="1024" height="608" class="alignnone size-large wp-image-6747" srcset="https://iotexpert.com/wp-content/uploads/2019/04/IMG_0433-1024x608.jpg 1024w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0433-600x356.jpg 600w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0433-300x178.jpg 300w, https://iotexpert.com/wp-content/uploads/2019/04/IMG_0433-768x456.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>In the next article I will:</p>
<ol>
<li>Speed up the SPI</li>
<li>Get rid of the hardware timer</li>
<li>Explain more about the EINK.</li>
</ol>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/cy8ckit-028-epd-and-modus-toolbox-1-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Embedded Graphics: TFT Displays &#038; Drivers</title>
		<link>https://iotexpert.com/embedded-graphics-tft-displays-drivers/</link>
					<comments>https://iotexpert.com/embedded-graphics-tft-displays-drivers/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Thu, 27 Dec 2018 13:29:21 +0000</pubDate>
				<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6404</guid>

					<description><![CDATA[Summary This article will take you through a high level overview of all of the parts of a TFT LCD display.  The vast majority of what I have read on the internet makes this whole issue massively complex.  I&#8217;m quite sure that this complexity problem is a real reflection of the serious design and manufacturing [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Summary</h2>



<p>This article will take you through a high level overview of all of the parts of a TFT LCD display.  The vast majority of what I have read on the internet makes this whole issue massively complex.  I&#8217;m quite sure that this complexity problem is a real reflection of the serious design and manufacturing complexity in these displays and drivers.  That being said, to get a conceptual understanding is much simpler, and is the point of this article.</p>
<p>A significant amount of my learning about this subject came from a 195 page powerpoint presentation by <a href="http://www.ioe.nchu.edu.tw/en/wb_introduction/wb_t_introduction_1.asp?sn=18&amp;cid=8" target="_blank" rel="noopener">Dr. Fang-Hsing Wang</a> entitled &#8220;<a href="http://web.nchu.edu.tw/pweb/users/fansen_wang/lesson/7043.pdf" target="_blank" rel="noopener">Flat Panel Display : Principle and Driving Circuit Design</a>&#8220;.  He has graciously allowed me to reproduce a few of his images.  This dude knows way way more about these circuits than I do and I would encourage you to read his work.</p>
<p>This article has the following subsections:</p>



<ol class="wp-block-list">
<li>TFT Pixel</li>
<li>TFT Pixel Schematic</li>
<li>TFT Panels (Also known as TFT Glass)</li>
<li>TFT Gate Drivers</li>
<li>TFT Source Drivers</li>
<li>Gamma</li>
<li>Multiplexing Gate and Source Drivers</li>
</ol>



<h2 class="wp-block-heading">TFT Pixel</h2>



<p>The fundamental element in a TFT display is the liquid crystal.  These elements have the property that the crystals will align from horizontal (which blocks the light) to vertical (which lets most of the light through) based on the electric field applied to them.  Basically, you shine light through the liquid crystal, which blocks some or all of the light, the remainder of the white light then goes through a color filter to make red, green, or blue. It works like this:</p>





<ol class="wp-block-list">
<li>You use an array of LEDs to shine white light from the back of the screen towards the front (your eyes) </li>
<li>Into a diffuser (to spread out the light and make it even)</li>
<li>You control the orientation of the crystals using a voltage to apply an electric field to the crystals</li>
<li>The white light from the back (often called the backlight) will shine through the liquid crystal elements.  The amount of light coming out will depend on the orientation of the crystals.</li>
<li>The white light coming out of the crystal will then go into a red, green or blue color filter making it red, green or blue (RGB)</li>
<li>The light from three RGB filters will combine in your eye into a color based on the amount of red, green and blue (purple in the case below)</li>
</ol>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="883" src="https://iotexpert.com/wp-content/uploads/2018/12/pixel-1-1024x883.png" alt="" class="wp-image-6412" srcset="https://iotexpert.com/wp-content/uploads/2018/12/pixel-1-1024x883.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/pixel-1-600x517.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/pixel-1-300x259.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/pixel-1-768x662.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/pixel-1.png 1185w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>This architecture means that every pixel in the display will require a red, green and blue element.  And, you will need to control the voltage on all of the elements (which will be quite a lot on a screen of any size)</p>



<p>Here is a nice cross section that I found on <a rel="noreferrer noopener" aria-label="Here is a nice cross section that I found on Innolux's website (opens in a new tab)" href="http://www.innolux.com/Pages/EN/Technology/TFT_LCD_EN.html" target="_blank">Innolux&#8217;s</a> website.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="657" height="312" src="https://iotexpert.com/wp-content/uploads/2018/12/tft_lcd-1.gif" alt="" class="wp-image-6419" /></figure>



<h2 class="wp-block-heading">Pixel Schematic</h2>



<p>What does the schematic for one element in a pixel look like?  And where is the T(transistor) in the TFT?  The three letter acronym TFT stands for a thin film transistor that is physically on the top of the LCD matrix right next to each liquid crystal element.  Here is a schematic model for one element in the array.  C-LC represents the capacitance of the liquid crystal.  CS is a storage capacitor that is used to hold the electric field across the liquid crystal when the transistor is OFF.   To apply a voltage across the LC you just turn on the gate and apply the correct voltage to the column commonly known as the source.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="864" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM-1024x864.png" alt="" class="wp-image-6421" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM-1024x864.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM-600x506.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM-300x253.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM-768x648.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-16-at-9.01.23-AM.png 1660w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>You should notice that the &#8220;back&#8221; terminal of the two capacitors is called &#8220;VCOM&#8221; and is physically on the other side of the liquid crystal matrix from the TFT.  All of the liquid crystal backsides in the display are connected to the same VCOM.  A bit of painfulness in this system is that the CS capacitor leaks, which means that the LCD changes state which means that each pixel must be updated, properly called refreshed, on a regular basis.</p>





<h2 class="wp-block-heading">TFT Panel</h2>



<p>We know that each pixel has three three thin film transistors, three capacitors, three color filters (red, green and blue) and that we need to control the voltage on the source/drain of each transistor in order to cause the right amount of light to come through the liquid crystal.  How do we do that?  The first step is to arrange all of the pixels in a matrix.  Each row of matrix has all of the gates connected together.  And each column of the matrix has all of the sources tied together.  In order to address a specific pixel RGB element, you turn on the correct row and then apply a voltage to the correct column at the right time.</p>
<p><a href="https://iotexpert.com/2018/12/27/embedded-graphics-tft-displays-drivers/graphicsystem-2/" rel="attachment wp-att-6434"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem-1024x584.png" alt="" width="1024" height="584" class="alignnone size-large wp-image-6434" srcset="https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem-1024x584.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem-600x342.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem-300x171.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem-768x438.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/graphicsystem.png 1278w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>





<p>If you have been thinking about this system you might have done a little bit of math and figured out that you are going to need an absolute boatload of source and gate driver signals.  And you would be right!  For example, a 4.3&#8243; screen with 480&#215;272 will require 480x272x3 elements which are probably organized into 480 rows by 816 columns.  This would require a chip with at least 480+816=1296 pins, that is a lot.  It turns out that for small screens &lt;=3.5&#8243; there are chips with enough pins to do the job.  But, for larger screens, it requires multiple chips to do the job.  The &#8220;&#8230;&#8221; in the picture above shows the driver chips being cascaded.  The next thing to know is that &#8220;TFT Glass&#8221; usually has the driver chip(s) embedded into the screen at the edge (you can see that in the picture from Innolux above).</p>





<h2 class="wp-block-heading">TFT Gate Drivers</h2>
<h2>

</h2>
<p>You must put a quite high voltage source &gt;20v and drain &lt;-10V across the liquid crystal at the right time to get it to do its thing.  In order to pass that source voltage, the gate must be turned on at the right time to the right voltage, this is the purpose of the Gate Driver IC.  The gate driver is conceptually simple and Dr. Wang drew a nice picture on page 7 of his presentation.  You can see that it is basically a shift register, with one element per gate.  You shift in a &#8220;1&#8221; and then clock it through the entire shift register which will have the effect of applying a 1 to each gate.</p>
<p><a href="https://iotexpert.com/2018/12/27/embedded-graphics-tft-displays-drivers/screen-shot-2018-12-22-at-8-48-08-am/" rel="attachment wp-att-6435"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-8.48.08-AM.png" alt="" width="997" height="748" class="alignnone size-full wp-image-6435" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-8.48.08-AM.png 997w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-8.48.08-AM-600x450.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-8.48.08-AM-300x225.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-8.48.08-AM-768x576.png 768w" sizes="auto, (max-width: 997px) 100vw, 997px" /></a></p>
<p>However, a 3.3v logic 1 is not anywhere high enough to drive the gate so that it can pass the much higher source voltage.  So, you need to level shifter and a buffer to get the &#8220;right&#8221; voltage.   On page 15, Dr. Wang made a nice picture of this circuit as well.</p>
<p><a href="https://iotexpert.com/2018/12/27/embedded-graphics-tft-displays-drivers/screen-shot-2018-12-22-at-9-08-48-am/" rel="attachment wp-att-6436"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-9.08.48-AM.png" alt="" width="998" height="744" class="alignnone size-full wp-image-6436" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-9.08.48-AM.png 998w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-9.08.48-AM-600x447.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-9.08.48-AM-300x224.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-22-at-9.08.48-AM-768x573.png 768w" sizes="auto, (max-width: 998px) 100vw, 998px" /></a></p>
<p>It turns out that this picture is conceptually correct, but the exact implementation has &#8220;a lot going on&#8221;.  You can read about the next layer of circuit design in his presentation on pages 15-35.</p>
<h2>

 TFT Source Drivers</h2>
<h2 class="wp-block-heading">

</h2>
<p>In its most basic form, the TFT source driver is responsible for taking an 8-bit digital input value representing the value of an individual LCD element and turning it into a voltage, the driving the voltage.  Like this:</p>
<p><a href="https://iotexpert.com/2018/12/27/embedded-graphics-tft-displays-drivers/column/" rel="attachment wp-att-6443"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/column.png" alt="" width="349" height="677" class="alignnone size-full wp-image-6443" srcset="https://iotexpert.com/wp-content/uploads/2018/12/column.png 349w, https://iotexpert.com/wp-content/uploads/2018/12/column-155x300.png 155w" sizes="auto, (max-width: 349px) 100vw, 349px" /></a></p>
<p>You could conceptually have one DAC per column in the panel.  But this would have at least two problems</p>
<ol>
<li>The DACs are big circuits and this would make for giant source driver chips</li>
<li>You would need to &#8220;save&#8221; all of the digital values for an entire row so that when you turned on the row, you could turn on all of the DACs on at the same time.</li>
</ol>
<p>You could conceptually also have one DAC for all of the columns, but this would have a bunch of problems including:</p>
<ol>
<li>The DAC would have to be strong enough to drive all of the columns</li>
<li>You would need 3x the number of row drivers to effectively de-mux the column</li>
<li>You would need 1 pin on the source driver per column in the panel (for an 800&#215;600 lcd that would be 600&#215;3 = 1800 pins)</li>
</ol>
<p>In reality there is some compromise of chip size, number of pins and time that is made by multiplexing pins, columns and rows.  For example, many of the small screens appear to have 1 column driver for all of the reds, 1 driver for the blues and one for greens. </p>
<p>What appears to happen in real life on bigger screens is some combination of column and row multiplexing.  In one display that I found there were 2x the number of rows which allows the columns to be multiplexed 2-1.  The display is 1024&#215;600.  That requires 1024*3 RGBs in the column = 1536 pins.  This means that you need to double the number of gate drivers, resulting in 1200 pins in the row direction.  Here is a picture from their datasheet.</p>
<p><a href="https://iotexpert.com/2018/12/27/embedded-graphics-tft-displays-drivers/ek79016/" rel="attachment wp-att-6444"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/ek79016-1024x769.png" alt="" width="1024" height="769" class="alignnone size-large wp-image-6444" srcset="https://iotexpert.com/wp-content/uploads/2018/12/ek79016-1024x769.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/ek79016-600x450.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/ek79016-300x225.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/ek79016-768x577.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/ek79016.png 1480w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Gamma Correction</h1>
<p>The last issue that I will address in TFT LCD drivers is called <a href="https://en.wikipedia.org/wiki/Gamma_correction" target="_blank" rel="noopener">Gamma Correction</a> or more simply Gamma.  Gamma is an intensity adjustment factor.  For any given digital intensity input, you will need a non-linear translation to a voltage output on the source.  For example a doubling of digital input (so that a pixel appears twice as bright) you will not double but instead will have some non-linear translation of the output voltage.</p>
<p>There appear to be a bunch of reason why you need Gamma Correction including at least:</p>
<ol>
<li>Your eye perceives light intensity in a non-linear way</li>
<li>The LCD panel responds differently based on the input</li>
<li>The intensity variance is dependent on the color</li>
</ol>
<p>The good news is that this gamma correction is built into the display drivers.  From my reading, this is sometimes done with digital processing, and sometimes done with an analog circuit.  But in general, it appears to be tuned and programmed into the driver by the panel vendor for these smaller display.</p>
<p>In the next article I will write about TFT Controllers.</p>





<p><span><h1>Embedded Graphics Index</h1>
<p><div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Embedded Graphics</th>
</tr>
</thead>
<tbody>
<tr><td >Embedded Graphics Overview</td>
</tr>

<tr><td >TFT Displays &amp; Drivers</td>
</tr>

<tr><td >TFT Controllers</td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 1</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/" target="_blank" rel="noopener">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 2</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/" target="_blank" rel="noopener">MCU Friend 3.5" Identification</a></td>
</tr>
</tbody></table></div></p></span></p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/embedded-graphics-tft-displays-drivers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MCU Friend 3.5 TFT Identification</title>
		<link>https://iotexpert.com/mcu-friend-3-5-tft-identification/</link>
					<comments>https://iotexpert.com/mcu-friend-3-5-tft-identification/#comments</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Tue, 04 Dec 2018 06:21:47 +0000</pubDate>
				<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6304</guid>

					<description><![CDATA[Summary I bought four MCU Friend 3.5&#8243; TFT shields.  And, unfortunately, they have spiraled me into a deep, dark place trying to figure out how to use them.  The the documentation consists of a sticker on the antistatic bag, a picture of the shield with a list of 5 different possible LCD drivers, a pinout, [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>I bought four MCU Friend 3.5&#8243; TFT shields.  And, unfortunately, they have spiraled me into a deep, dark place trying to figure out how to use them.  The the documentation consists of a sticker on the antistatic bag, a picture of the shield with a list of 5 different possible LCD drivers, a pinout, and a block of code that supposedly represents the startup code.  The unfortunate part is that none of these have been exactly right &#8211; they all have errors.  This article is a description of the journey to figuring out how to use them.</p>
<p>This article has the following parts:</p>
<ol>
<li>MCU Friend 3.5&#8243; Documentation</li>
<li>MCU Friend 3.5&#8243; Shields</li>
<li>Using the MCUFRIEND_kbv Library</li>
<li>Identify the LCD Driver with Register Reads</li>
<li>A PSoC Program To Identify LCD Controllers</li>
<li>Using the MCUFriend_kbv Startup Code</li>
<li>Use the Web Startup</li>
<li>Conclusion</li>
</ol>
<h1>MCU Friend 3.5&#8243; Documentation</h1>
<p>Here is a picture of the bag. (the QR code is a number &#8220;181024202132&#8221; which I thought might be a phone number but isn&#8217;t.  It also doesn&#8217;t match anything in google, so i&#8217;m not sure what it is.</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0035/" rel="attachment wp-att-6313"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0035-e1543435690537-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6313 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0035-e1543435690537-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0035-e1543435690537-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0035-e1543435690537-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0035-e1543435690537-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>This text on the website says:</p>
<p><span><strong>Features:</strong></span></p>
<ul>
<li><span><strong>  5inch TFT LCD Module, Resolution 480&#215;320, Controller ili9481 ili9468, ili9488 hx8357, or r61581.</strong></span></li>
<li><span><strong>     Designed with a TF(Micro SD) card socket on the back of board so that you can conveniently insert a card.</strong></span></li>
<li><span><strong>     Support touch screen function.</strong></span></li>
<li><span><strong>     The test code is provided below.</strong></span></li>
<li><span><strong>     This kit requires certain professional knowledge and ability, make sure you know how to use it, please. We cannot provide any technical assistance.</strong></span></li>
</ul>
<p><span><strong>Specifications:</strong></span></p>
<p><span><strong>Controller: ili9481 ili9468, ili9488 hx8357, or r61581</strong></span></p>
<p><span><strong>Resolution: 480&#215;320</strong></span></p>
<p><span><strong>Voltage: 5V/3.3V</strong></span></p>
<p><span><strong>Package Include: 1 x LCD Module</strong></span></p>
<p>The website also has this code which they claim is the startup code.  It is interesting that</p>
<ol>
<li>There are several lines are commented out</li>
<li>It implies that you have a  SPI interface</li>
<li>When you look at the commands some of them don&#8217;t exist in some of the controllers</li>
</ol>
<pre class="lang:c decode:true">write_SPI_commond(0xFF);
write_SPI_commond(0xFF);
delay_nms(5);
write_SPI_commond(0xFF);
write_SPI_commond(0xFF);
write_SPI_commond(0xFF);
write_SPI_commond(0xFF);
delay_nms(10);
write_SPI_commond(0xB0);
write_SPI_data(0x00);
write_SPI_commond(0xB3);
write_SPI_data(0x02);
write_SPI_data(0x00);
write_SPI_data(0x00);
write_SPI_data(0x10);
write_SPI_commond(0xB4);
write_SPI_data(0x11);//0X10
write_SPI_commond(0xC0);
write_SPI_data(0x13);
write_SPI_data(0x3B);//
write_SPI_data(0x00);
write_SPI_data(0x00);
write_SPI_data(0x00);
write_SPI_data(0x01);
write_SPI_data(0x00);//NW
write_SPI_data(0x43);
write_SPI_commond(0xC1);
write_SPI_data(0x08);
write_SPI_data(0x15);//CLOCK
write_SPI_data(0x08);
write_SPI_data(0x08);
write_SPI_commond(0xC4);
write_SPI_data(0x15);
write_SPI_data(0x03);
write_SPI_data(0x03);
write_SPI_data(0x01);
write_SPI_commond(0xC6);
write_SPI_data(0x02);
write_SPI_commond(0xC8);
write_SPI_data(0x0c);
write_SPI_data(0x05);
write_SPI_data(0x0A);//0X12
write_SPI_data(0x6B);//0x7D
write_SPI_data(0x04);
write_SPI_data(0x06);//0x08
write_SPI_data(0x15);//0x0A
write_SPI_data(0x10);
write_SPI_data(0x00);
write_SPI_data(0x31);//0x23
write_SPI_data(0x10);
write_SPI_data(0x15);//0x0A
write_SPI_data(0x06);//0x08
write_SPI_data(0x64);//0x74
write_SPI_data(0x0D);//0x0B
write_SPI_data(0x0A);//0x12
write_SPI_data(0x05);//0x08
write_SPI_data(0x0C);//0x06
write_SPI_data(0x31);//0x23
write_SPI_data(0x00);
write_SPI_commond(0x35);
write_SPI_data(0x00);
//write_SPI_commond(0x36);
//write_SPI_data(0x00);
write_SPI_commond(0x0C);
write_SPI_data(0x66);
write_SPI_commond(0x3A);
write_SPI_data(0x66);
write_SPI_commond(0x44);
write_SPI_data(0x00);
write_SPI_data(0x01);
write_SPI_commond(0xD0);
write_SPI_data(0x07);
write_SPI_data(0x07);//VCI1
write_SPI_data(0x14);//VRH 0x1D
write_SPI_data(0xA2);//BT 0x06
write_SPI_commond(0xD1);
write_SPI_data(0x03);
write_SPI_data(0x5A);//VCM  0x5A
write_SPI_data(0x10);//VDV
write_SPI_commond(0xD2);
write_SPI_data(0x03);
write_SPI_data(0x04);//0x24
write_SPI_data(0x04);
write_SPI_commond(0x11);
delay_nms(150);
write_SPI_commond(0x2A);
write_SPI_data(0x00);
write_SPI_data(0x00);
write_SPI_data(0x01);
write_SPI_data(0x3F);//320
write_SPI_commond(0x2B);
write_SPI_data(0x00);
write_SPI_data(0x00);
write_SPI_data(0x01);
write_SPI_data(0xDF);//480
//write_SPI_commond(0xB4);
//write_SPI_data(0x00);
delay_nms(100);
write_SPI_commond(0x29);
delay_nms(30);
write_SPI_commond(0x2C);</pre>
<p>It also has a picture which says the LCD has one of several different controllers (and after digging in I know for a fact that two of mine were made by Raydium and are not on the list)</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/5a79edf400c71142089966/" rel="attachment wp-att-6315"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966.jpg" alt="" width="1001" height="1001" class="alignnone size-full wp-image-6315" srcset="https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966.jpg 1001w, https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966-300x300.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966-100x100.jpg 100w, https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966-600x600.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966-150x150.jpg 150w, https://iotexpert.com/wp-content/uploads/2018/11/5a79edf400c71142089966-768x768.jpg 768w" sizes="auto, (max-width: 1001px) 100vw, 1001px" /></a></p>
<p>And finally a table of pins.  Which is interesting as it lists 37 pins when the shield has no where near that number.  And it shows the shield as  16-bit interface which it isnt &#8230; and it shows some LEDs which aren&#8217;t there either.</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/screen-shot-2018-11-28-at-3-15-52-pm/" rel="attachment wp-att-6316"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-28-at-3.15.52-PM-330x1024.png" alt="" width="330" height="1024" class="alignnone size-large wp-image-6316" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-28-at-3.15.52-PM-330x1024.png 330w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-28-at-3.15.52-PM-97x300.png 97w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-28-at-3.15.52-PM.png 367w" sizes="auto, (max-width: 330px) 100vw, 330px" /></a></p>
<h1>MCU Friend 3.5&#8243; Shields</h1>
<p>I bought 4 different shields.  One came broken.  The other three are all different.  When you look at the boards there are two visibly different configurations</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0030/" rel="attachment wp-att-6305"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0030-e1543400017985-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6305 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0030-e1543400017985-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0030-e1543400017985-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0030-e1543400017985-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0030-e1543400017985-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a>  <a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0028-2/" rel="attachment wp-att-6307"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0028-e1543400079515-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6307 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0028-e1543400079515-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0028-e1543400079515-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0028-e1543400079515-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0028-e1543400079515-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Using the MCUFRIEND_kbv Library</h1>
<p>The first thing I did was try to use the MCUFRIEND_kbv library to see if the screens worked.  The first board identified as ID=0x9403 and did not work.  Apparently, the tool just spits out the ID if it doesn&#8217;t know it, which it did not.</p>
<p>One of the boards identified as ID=0x6814 worked perfectly, and one had a blue cast to all of the screens.  The crazy part is the two boards that identified as ID=0x6814 had different PCBs.  According to the comments in the MCUFRIEND_kbv.cpp ID=0x6814 is an RM68140 and ID=9403 is unknown.</p>
<p>Here is the one with the blue cast:</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0034/" rel="attachment wp-att-6310"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0034-e1543400790425-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6310 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0034-e1543400790425-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0034-e1543400790425-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0034-e1543400790425-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0034-e1543400790425-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Here is the functional one:</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0033/" rel="attachment wp-att-6311"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0033-e1543400819853-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6311 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0033-e1543400819853-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0033-e1543400819853-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0033-e1543400819853-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0033-e1543400819853-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Identify with Register Reads</h1>
<p>Next, I started down the path of trying to figure out what the controllers were by using register reads.  David Prentice (the guy who wrote/maintains the MCU Friend_kbv Arduino library) has an absolute ton of responses on the Arduino forum trying to help people figure out what their shield is.  He asks them to post the register report from his example program LCD_ID_readnew which is included as an example in the library.</p>
<p>When you look at these LCD controllers they all have some variant of &#8220;Read ID&#8221; which responds with 1-6 bytes.  The basic idea of this program is to look at what bytes are returned to try to identify the controller.  Here is an example of what I got when I ran the LCD_ID_readnew program on my shields:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">reg(0x0000) 00 00       ID: ILI9320, ILI9325, ILI9335, ...
reg(0x0004) 54 54 80 66 Manufacturer ID
reg(0x0009) 00 00 61 00 00           Status Register
reg(0x000A) 08 08 Get Powsr Mode
reg(0x000C) 66 66 Get Pixel Format
reg(0x0030) 00 00 00 01 DF  PTLAR
reg(0x0033) 00 00 00 01 E0 00 00        VSCRLDEF
reg(0x0061) 00 00 RDID1 HX8347-G
reg(0x0062) 00 00 RDID2 HX8347-G
reg(0x0063) 00 00 RDID3 HX8347-G
reg(0x0064) 00 00 RDID1 HX8347-A
reg(0x0065) 00 00 RDID2 HX8347-A
reg(0x0066) 00 00 RDID3 HX8347-A
reg(0x0067) 00 00 RDID Himax HX8347-A
reg(0x0070) 00 00 Panel Himax HX8347-A
reg(0x00A1) 00 00 00 00 00    RD_DDB SSD1963
reg(0x00B0) 00 00 RGB Interface Signal Control
reg(0x00B3) 00 00 11 00 00      Frame Memory
reg(0x00B4) 00 00 Frame Mode
reg(0x00B6) 02 02 02 3B 00      Display Control
reg(0x00B7) 06 06 Entry Mode Set
reg(0x00BF) FF FF 68 14 00 FF   ILI9481, HX8357-B
reg(0x00C0) 0E 0E 0E 00 00 00 00 00 00   Panel Control
reg(0x00C1) 04 04 00 00 Display Timing
reg(0x00C5) 00 00 Frame Rate
reg(0x00C8) 00 00 00 00 00 00 00 00 00 00 00 00 00      GAMMA
reg(0x00CC) 00 00 Panel Control
reg(0x00D0) 00 00 00 00 Power Control
reg(0x00D1) 00 00 00 00 VCOM Control
reg(0x00D2) 00 00 00 Power Normal
reg(0x00D3) 00 00 94 86    ILI9341, ILI9488
reg(0x00D4) 00 00 00 00    Novatek
reg(0x00DA) 54 54 RDID1
reg(0x00DB) 80 80 RDID2
reg(0x00DC) 66 66 RDID3
reg(0x00E0) 00 00 54 07 44 05 08 00 54 07 44 05 08 44 44 00     GAMMA-P
reg(0x00E1) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     GAMMA-N
reg(0x00EF) 00 00 00 00 00 00 ILI9327
reg(0x00F2) 00 00 00 00 00 00 00 00 00 00 00 00 Adjust Control 2
reg(0x00F6) 00 00 00 00 Interface Control
</pre>
<p>The key thing to see in this output is the register 0x04 which says 54,80,66 which identifies this as a Raydium RM68140 LCD controller.  Here is a snapshot from the data sheet.</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/screen-shot-2018-12-04-at-5-08-31-am/" rel="attachment wp-att-6331"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM-1024x311.png" alt="" width="1024" height="311" class="alignnone size-large wp-image-6331" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM-1024x311.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM-600x182.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM-300x91.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM-768x233.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.08.31-AM.png 1818w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Unfortunately, the next thing to notice is that Register 0xBF has reg(0x00BF) FF FF 68 14 00 FF.  The unfortunate part is that this register is not documented in the data sheet beyond this one reference:</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/screen-shot-2018-12-04-at-5-17-46-am/" rel="attachment wp-att-6332"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM-1024x49.png" alt="" width="1024" height="49" class="alignnone size-large wp-image-6332" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM-1024x49.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM-600x29.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM-300x14.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM-768x37.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.17.46-AM.png 1744w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Presumably the &#8220;68 14&#8221; corresponds to a Raydium 68140, but who knows?  When I posted this on the <a href="http://forum.arduino.cc/index.php?topic=582666.0" target="_blank" rel="noopener">Arduino forum</a>, David Prentice responded (David does yeoman&#8217;s labor helping people and should be Thanked for all of his pro-bono work and putting up with a bunch of really bad questions)</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/screen-shot-2018-12-04-at-5-33-00-am/" rel="attachment wp-att-6335"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM-1024x432.png" alt="" width="1024" height="432" class="alignnone size-large wp-image-6335" srcset="https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM-1024x432.png 1024w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM-600x253.png 600w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM-300x127.png 300w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM-768x324.png 768w, https://iotexpert.com/wp-content/uploads/2018/12/Screen-Shot-2018-12-04-at-5.33.00-AM.png 1934w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>After digging some more, I decided that it is super ugly out there, as you find that there are a significant number of LCD controllers that are clones, copies, pirated etc&#8230; and that they all present themselves differently.  And, in hindsight I think that this is the reason that my ILI9341 from the <a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/">previous</a> article doesnt quite work correctly.</p>
<h1>A PSoC Program To Identify LCD Controllers</h1>
<p>The next thing that I did was create a PSoC Program to read registers from the controllers to try to figure out what they were.  My original plan was to write a complete identification program, but I have largely decided that this is a waste of time (more on this later).  Here is the beginning of the project, it is called &#8220;Identify&#8221; in the workspace.</p>
<p>First, a function to reset the screen by toggling the reset line on the controller, then sending a command &#8220;0x01&#8221; which is commonly a software reset.   It turns out that I spent a bunch of time trying to figure out what was going on because I was not getting any responses from the controllers.  This was caused by not sending the software reset, which at least in two of the cases makes them unresponsive.</p>
<pre class="start-line:7 EnlighterJSRAW" data-enlighter-language="c" ">#define LCD_COMMAND (0)
#define LCD_DATA (1)

void lcdReset()
{
       /* Reset - High, Low (reset), High */
    Cy_GPIO_Set(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    CyDelay(200);
    Cy_GPIO_Clr(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    CyDelay(200);
    Cy_GPIO_Set(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    CyDelay(200);
   
    GraphicLCDIntf_1_Write8(LCD_COMMAND,0x01);
 
}

void regReadPrint(uint8_t reg,uint8_t *buff,uint16_t num)
{
    GraphicLCDIntf_1_Write8(LCD_COMMAND,reg);
    GraphicLCDIntf_1_ReadM8(LCD_DATA,buff,num);
    printf("%02X ",reg);
    for(int i=0;i&lt;num;i++)
    {
        printf("0x%02X,",buff[i]);
    }
    printf("\r\n");
    
}</pre>
<p>Then I built a command line interface that queries the typical registers:</p>
<pre class="start-line:37 lang:c decode:true ">int main(void)
{
    uint8_t buff[128];

    __enable_irq(); /* Enable global interrupts. */

    UART_Start();
    setvbuf( stdin, NULL, _IONBF, 0 );
    printf("Started\r\n");
    
    GraphicLCDIntf_1_Start();
    lcdReset();
    
    while(1)
    {
        char c;
        c=getchar();
        
        switch(c)
        {  
            case 'a':
                regReadPrint(0x04,buff,6);
                regReadPrint(0xA1,buff,6);
                regReadPrint(0xBF,buff,6);
                regReadPrint(0xDA,buff,1);
                regReadPrint(0xDB,buff,1);
                regReadPrint(0xDC,buff,1);
                regReadPrint(0xd3,buff,6);
            break;
</pre>
<p>When I ran this program on the three controllers here is what I got:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">Screen 1:
04 0x00,0x00,0x94,0x03,0x00,0x00,
A1 0x00,0x00,0x00,0x00,0x00,0x00,
BF 0x00,0x00,0x00,0x00,0x00,0x00,
DA 0x00,
DB 0x94,
DC 0x03,
D3 0x00,0x00,0x94,0x03,0x00,0x00,

Screen 2: Raydium 68140 (arduino works)
04 0x54,0x54,0x80,0x66,0x00,0x00,
BF 0xFF,0xFF,0x68,0x14,0x00,0xFF,
DA 0x54,
DB 0x80,
DC 0x66,
D3 0x00,0x00,0x94,0x86,0x00,0x00,

Screen 3: Raydium 68140 (looks blue)
04 0x54,0x54,0x80,0x66,0x00,0x00,
BF 0xFF,0xF7,0x60,0x14,0x00,0xFF,
DA 0x54,
DB 0x80,
DC 0x66,
D3 0x00,0x00,0x94,0x86,0x00,0x00,</pre>
<p>So, where does this leave me?</p>
<ol>
<li>I have no idea what Screen 1 is?  04 0x00,0x00,0x94,0x03,0x00,0x00,</li>
<li>Two of them appear to be Raydium RM68140s</li>
<li>The two Raydiums have different register values for 0xBF</li>
</ol>
<p>And all of this is insane because most of these companies don&#8217;t appear to have coherent websites or generally available datasheets.  I suppose that it would help if I spoke and read Chinese.</p>
<h1>Using the MCUFriend_kbv Startup Code</h1>
<p>The next thing that I did was try out the startup code that MCUFriend_kbv generates.  I used the same technique from <a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/" target="_blank" rel="noopener">PSoC 6 + Segger EmWin + MCUFriend 2.4&#8243; Part 1</a> and spit out the startup bytes.  Here they are:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="c">0x1,0x0, 
0x28,0x0, 
0x3A,0x1,0x55, 
0x3A,0x1,0x55, 
0x11,0x0, 
0x29,0x0, 
0xB6,0x3,0x0,0x22,0x3B, 
0x36,0x1,0x8, 
0x2A,0x4,0x0,0x0,0x1,0x3F, 
0x2B,0x4,0x0,0x0,0x1,0xDF, 
0x33,0x6,0x0,0x0,0x1,0xE0,0x0,0x0, 
0x37,0x2,0x0,0x0, 
0x13,0x0, 
0x20,0x0, 
</pre>
<p>And this is what it looks like in my PSoC program:</p>
<pre class="start-line:186 EnlighterJSRAW" data-enlighter-language="c" ">static const uint8_t mcu35_init_sequence_kbv[]  = {
    0x1,0x0,                            // Software Reset
    0x28,0x0,                           // Display Off
    0x3A,0x1,0x55,                      // Pixel Format Set 565
    0x3A,0x1,0x55,                      // Pixel Format Set 565
    0x11,0x0,                           // Sleep Out
    0x29,0x0,                           // Display On
    0xB6,0x3,0x0,0x22,0x3B,             // Display Function Control
    0x36,0x1,0x8,                       // Memory Access Control
    0x2A,0x4,0x0,0x0,0x1,0x3F,          // Column Set Address 320
    0x2B,0x4,0x0,0x0,0x1,0xDF,          // Page Set Addres 480
    0x33,0x6,0x0,0x0,0x1,0xE0,0x0,0x0,  // Vertical Scrolling Definition
    0x37,0x2,0x0,0x0,                   // Vertical Scrolling Start Address
    0x13,0x0,                           // Normal Display On
    0x20,0x0,                           // Display Inversion Off
};</pre>
<p>When I run this things look like this:</p>
<p>Screen 1: Looks good, just need to flip the x-axis</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0037/" rel="attachment wp-att-6339"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0037-1024x557.jpg" alt="" width="1024" height="557" class="alignnone size-large wp-image-6339" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0037-1024x557.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0037-600x326.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0037-300x163.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0037-768x418.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 2: Looks good, just need to flip the y-axis</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0038/" rel="attachment wp-att-6340"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0038-1024x537.jpg" alt="" width="1024" height="537" class="alignnone size-large wp-image-6340" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0038-1024x537.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0038-600x315.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0038-300x157.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0038-768x403.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 3: Not good&#8230; not exactly sure how to fix.</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0039/" rel="attachment wp-att-6341"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0039-1024x510.jpg" alt="" width="1024" height="510" class="alignnone size-large wp-image-6341" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0039-1024x510.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0039-600x299.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0039-300x149.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0039-768x383.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Use the Web Startup</h1>
<p>Well, things still aren&#8217;t quite right, so for some strange reason, I keep going and try to use the startup code from the web.  In order to make it work I translate</p>
<ul>
<li>delay_nms &#8211;&gt; CyDelay</li>
<li>write_SPI_commond &#8211;&gt; GraphicLCDIntf_1_Write8_A0</li>
<li>write_SPI_data &#8211;&gt; GraphicLCDIntf_1_Write8_A1</li>
</ul>
<p>Here is the updated code:</p>
<pre class="start-line:259 EnlighterJSRAW" data-enlighter-language="c"">static void _InitController35Web()
{
    GraphicLCDIntf_1_Write8_A0(0xFF);
    GraphicLCDIntf_1_Write8_A0(0xFF);
    CyDelay(5);
    GraphicLCDIntf_1_Write8_A0(0xFF);
    GraphicLCDIntf_1_Write8_A0(0xFF);
    GraphicLCDIntf_1_Write8_A0(0xFF);
    GraphicLCDIntf_1_Write8_A0(0xFF);
    CyDelay(10);
    //0xB0,0x01,0x00,
    GraphicLCDIntf_1_Write8_A0(0xB0); //0
    GraphicLCDIntf_1_Write8_A1(0x00);
    
    //0xB3,0x04,0x02,0x00,0x00,0x10,
    GraphicLCDIntf_1_Write8_A0(0xB3); //1
    GraphicLCDIntf_1_Write8_A1(0x02);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x10);
    
    //0xB4,0x01,0x11,
    GraphicLCDIntf_1_Write8_A0(0xB4); // 2
    GraphicLCDIntf_1_Write8_A1(0x11);//0X10

    // 0xC0,0x08,0x13,0x3B,0x00,0x00,0x00,0x01,0x00,0x43,
    GraphicLCDIntf_1_Write8_A0(0xC0);
    GraphicLCDIntf_1_Write8_A1(0x13);
    GraphicLCDIntf_1_Write8_A1(0x3B);//
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x01);
    GraphicLCDIntf_1_Write8_A1(0x00);//NW
    GraphicLCDIntf_1_Write8_A1(0x43);

    // 0xC1,0x04,0x08,0x15,0x08,0x08,
    GraphicLCDIntf_1_Write8_A0(0xC1);
    GraphicLCDIntf_1_Write8_A1(0x08);
    GraphicLCDIntf_1_Write8_A1(0x15);//CLOCK
    GraphicLCDIntf_1_Write8_A1(0x08);
    GraphicLCDIntf_1_Write8_A1(0x08);

    // 0xC4,0x04,0x15,0x03,0x03,0x01
    GraphicLCDIntf_1_Write8_A0(0xC4);
    GraphicLCDIntf_1_Write8_A1(0x15);
    GraphicLCDIntf_1_Write8_A1(0x03);
    GraphicLCDIntf_1_Write8_A1(0x03);
    GraphicLCDIntf_1_Write8_A1(0x01);

    // 0xC6,0x01,0x02
    GraphicLCDIntf_1_Write8_A0(0xC6);
    GraphicLCDIntf_1_Write8_A1(0x02);

    // 0xC8,0x15,0x0C,0x05,0x0A,0x6B,0x04,0x06,0x15,0x10,0x00,0x31,0x10,0x15,0x06,0x64,0x0D,0x0A,0x05,0x0C,0x31,0x00
    GraphicLCDIntf_1_Write8_A0(0xC8);
    GraphicLCDIntf_1_Write8_A1(0x0c);
    GraphicLCDIntf_1_Write8_A1(0x05);
    GraphicLCDIntf_1_Write8_A1(0x0A);//0X12
    GraphicLCDIntf_1_Write8_A1(0x6B);//0x7D
    GraphicLCDIntf_1_Write8_A1(0x04);
    GraphicLCDIntf_1_Write8_A1(0x06);//0x08
    GraphicLCDIntf_1_Write8_A1(0x15);//0x0A
    GraphicLCDIntf_1_Write8_A1(0x10);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x31);//0x23
    GraphicLCDIntf_1_Write8_A1(0x10);
    GraphicLCDIntf_1_Write8_A1(0x15);//0x0A
    GraphicLCDIntf_1_Write8_A1(0x06);//0x08
    GraphicLCDIntf_1_Write8_A1(0x64);//0x74
    GraphicLCDIntf_1_Write8_A1(0x0D);//0x0B
    GraphicLCDIntf_1_Write8_A1(0x0A);//0x12
    GraphicLCDIntf_1_Write8_A1(0x05);//0x08
    GraphicLCDIntf_1_Write8_A1(0x0C);//0x06
    GraphicLCDIntf_1_Write8_A1(0x31);//0x23
    GraphicLCDIntf_1_Write8_A1(0x00);

    // 0x35,0x01,0x00
    GraphicLCDIntf_1_Write8_A0(0x35);
    GraphicLCDIntf_1_Write8_A1(0x00);
    //GraphicLCDIntf_1_Write8_A0(0x36);
    //GraphicLCDIntf_1_Write8_A1(0x00);

    // 0x0C,0x01,x066
    GraphicLCDIntf_1_Write8_A0(0x0C);
    GraphicLCDIntf_1_Write8_A1(0x66);

    //0x3A,0x01,0x55
    GraphicLCDIntf_1_Write8_A0(0x3A);
    GraphicLCDIntf_1_Write8_A1(0x55); // ARH changed to 565
    //GraphicLCDIntf_1_Write8_A1(0x66);

    // 0x44,0x02,0x00,0x01
    GraphicLCDIntf_1_Write8_A0(0x44);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x01);

    // 0xD0,0x04,0x07,0x07,0x14,0xA2,
    GraphicLCDIntf_1_Write8_A0(0xD0);
    GraphicLCDIntf_1_Write8_A1(0x07);
    GraphicLCDIntf_1_Write8_A1(0x07);//VCI1
    GraphicLCDIntf_1_Write8_A1(0x14);//VRH 0x1D
    GraphicLCDIntf_1_Write8_A1(0xA2);//BT 0x06


    // 0xD1,0x03,0x03,0x5A,0x10 
    GraphicLCDIntf_1_Write8_A0(0xD1);
    GraphicLCDIntf_1_Write8_A1(0x03);
    GraphicLCDIntf_1_Write8_A1(0x5A);//VCM  0x5A
    GraphicLCDIntf_1_Write8_A1(0x10);//VDV

    // 0xD2,0x03,0x03,0x04,0x04,
    GraphicLCDIntf_1_Write8_A0(0xD2);
    GraphicLCDIntf_1_Write8_A1(0x03);
    GraphicLCDIntf_1_Write8_A1(0x04);//0x24
    GraphicLCDIntf_1_Write8_A1(0x04);

    // 0x11,0x00,
    GraphicLCDIntf_1_Write8_A0(0x11);
    CyDelay(150);


    // 0x2A,0x04,0x00,0x00,0x01,0x3F
    GraphicLCDIntf_1_Write8_A0(0x2A);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x01);
    GraphicLCDIntf_1_Write8_A1(0x3F);//320


    // 0x2B,0x04,0x00,0x00,0x01,0xDF
    GraphicLCDIntf_1_Write8_A0(0x2B);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x00);
    GraphicLCDIntf_1_Write8_A1(0x01);
    GraphicLCDIntf_1_Write8_A1(0xDF);//480
    //GraphicLCDIntf_1_Write8_A0(0xB4);
    //GraphicLCDIntf_1_Write8_A1(0x00);
    
    CyDelay(100);

    // 0x29,0x00
    GraphicLCDIntf_1_Write8_A0(0x29);
    CyDelay(30);


    // 0x2C,0x00
    GraphicLCDIntf_1_Write8_A0(0x2C);
}
</pre>
<p>Here is what I get:</p>
<p>Screen1: Looks good, but inverted (I know how to fix)</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0042/" rel="attachment wp-att-6344"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0042-1024x525.jpg" alt="" width="1024" height="525" class="alignnone size-large wp-image-6344" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0042-1024x525.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0042-600x307.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0042-300x154.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0042-768x393.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 2: Looks right, except for the blue-line at the top (who knows)</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0041/" rel="attachment wp-att-6343"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0041-1024x520.jpg" alt="" width="1024" height="520" class="alignnone size-large wp-image-6343" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0041-1024x520.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0041-600x305.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0041-300x152.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0041-768x390.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 3: Seriously jacked</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0040/" rel="attachment wp-att-6342"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0040-1024x486.jpg" alt="" width="1024" height="486" class="alignnone size-large wp-image-6342" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0040-1024x486.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0040-600x285.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0040-300x142.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0040-768x364.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Earlier I told you that I much preferred to use the more compact startup code.  In order to match this, I decided to add a new code &#8220;0xDD&#8221; which means delay.  (I hope that there are no controllers out there that use 0XDD).  Here is the updated function:</p>
<pre class="start-line:157 EnlighterJSRAW" data-enlighter-language="c"">static void sendStartSequence(const uint8_t *buff,uint32_t len)
{
    for(unsigned int i=0;i&lt;len;i++)
    {
        if(buff[i] == 0xDD) // 
        {
            CyDelay(buff[i+1]);
            i=i+1;
        }
        else
        {
            GraphicLCDIntf_1_Write8_A0(buff[i]);
            i=i+1;
            unsigned int count;
            count = buff[i];
            for(unsigned int j=0;j&lt;count;j++)
            {
                i=i+1;
                GraphicLCDIntf_1_Write8_A1(buff[i]);
            }
        }
    }
}
</pre>
<p>And when I translate the web based startup code, here is what it looks like:</p>
<pre class="start-line:220 EnlighterJSRAW" data-enlighter-language="c" ">static const uint8_t mcu35_init_sequence_web[]  = {
    0xFF,0x00,          // ?
    0xFF,0x00,          // ?
    0xDD,5,             // Delay 5
    0xFF,0x00,          //
    0xFF,0x00,          //
    0xFF,0x00,          //
    0xFF,0x00,          // ?
    0xDD,10,            // delay 10
    //  
    0xB0,0x01,0x00,                                     // IF Mode control
    0xB3,0x04,0x02,0x00,0x00,0x10,                      // Frame Rate Control - only 2 paramters
    0xB4,0x01,0x11,                                     // Display inversion control 
    0xC0,0x08,0x13,0x3B,0x00,0x00,0x00,0x01,0x00,0x43,  // Power Control 1
    0xC1,0x04,0x08,0x15,0x08,0x08,                      // Power Control 2
    0xC4,0x04,0x15,0x03,0x03,0x01,                      // ?
    0xC6,0x01,0x02,                                     // ?
    // ??
    0xC8,0x15,0x0C,0x05,0x0A,0x6B,0x04,0x06,0x15,0x10,0x00,0x31,0x10,0x15,0x06,0x64,0x0D,0x0A,0x05,0x0C,0x31,0x00,
    0x35,0x01,0x00,                     // Tearing Effect 
    0x0C,0x01,0x66,                     // Read pixel format?
    0x3A,0x01,0x55,                     // Pixel Format Set
    
    0x44,0x02,0x00,0x01,                // Set Tear Scanline
    0xD0,0x04,0x07,0x07,0x14,0xA2,      // NVM Write
    0xD1,0x03,0x03,0x5A,0x10,           // NVM Protection Key
    0xD2,0x03,0x03,0x04,0x04,           // NVM Status Read

    0x11,0x00,                          // Sleep Out
    0xDD,150,                           // Delay 150ms
    0x2A,0x04,0x00,0x00,0x01,0x3F,      // Column Set Address 320
    0x2B,0x04,0x00,0x00,0x01,0xDF,      // Page Set Address   480
    0xDD,100,                           // Delay 100ms
    0x29,0x00,                          // Display On
    0xDD,30,                            // delay 30ms
    0x2C,0x00                           // Memory Write
};
</pre>
<p>Notice that my comments on the commands show that there are a bunch of them I dont know what they mean.  Moreover, the MIPI spec says that all of the commands after 0xAF are reserved for the manufacturer&#8230; so I am pretty sure that they don&#8217;t do anything, or maybe should&#8217;nt be used?.  The last thing that I decide to do is edit out the stuff that does not seem to make sense.  Here is the new sequence:</p>
<pre class="start-line:259 EnlighterJSRAW" data-enlighter-language="c" ">static const uint8_t mcu35_init_sequence_web_edited[]  = {
    0x35,0x01,0x00,                     // Tearing Effect 
    0x3A,0x01,0x55,                     // Pixel Format Set
    0x44,0x02,0x00,0x01,                // Set Tear Scanline
    0x11,0x00,                          // Sleep Out
    0xDD,150,                           // Delay 150ms
    0x2A,0x04,0x00,0x00,0x01,0x3F,      // Column Set Address 320
    0x2B,0x04,0x00,0x00,0x01,0xDF,      // Page Set Address   480
    0xDD,100,                           // Delay 100ms
    0x29,0x00,                          // Display On
    0xDD,30,                            // delay 30ms
};</pre>
<p>When I run this code I get the following screens:</p>
<p>Screen 1: Looks good, but inverted</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0043/" rel="attachment wp-att-6346"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0043-1024x500.jpg" alt="" width="1024" height="500" class="alignnone size-large wp-image-6346" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0043-1024x500.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0043-600x293.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0043-300x146.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0043-768x375.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 2: Looks good (one of those codes created the blue line that is now gone)</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0044/" rel="attachment wp-att-6347"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0044-1024x510.jpg" alt="" width="1024" height="510" class="alignnone size-large wp-image-6347" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0044-1024x510.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0044-600x299.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0044-300x150.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0044-768x383.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Screen 3: Color screwed up</p>
<p><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/img_0045/" rel="attachment wp-att-6348"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0045-1024x512.jpg" alt="" width="1024" height="512" class="alignnone size-large wp-image-6348" srcset="https://iotexpert.com/wp-content/uploads/2018/12/IMG_0045-1024x512.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0045-600x300.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0045-300x150.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/12/IMG_0045-768x384.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Conclusion</h1>
<p>At this point I have spent a frightening amount of time figuring out how these screens work.  Although it has been a good learning experience, I have generally decided that using unknown displays from China with LCD drivers of questionable origin is not worth the pain of trying to sort out the interface.  Beyond that:</p>
<ol>
<li>emWin seems to be able to talk to the RM68140 even though it is not listed as a supported chip</li>
<li>I have no idea what to do about screen 3.  Is it physically broken? Or do I just not know how to talk to it?</li>
<li>There many counterfeit chips out there.. and although they may work, it probably isnt worth the effort</li>
<li>David Prentice has added a lot of value for no personal gain by supporting the Arduino library MCUFriend_kbv</li>
</ol>
<p><span><h1>Embedded Graphics Index</h1>
<p><div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Embedded Graphics</th>
</tr>
</thead>
<tbody>
<tr><td >Embedded Graphics Overview</td>
</tr>

<tr><td >TFT Displays &amp; Drivers</td>
</tr>

<tr><td >TFT Controllers</td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 1</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/" target="_blank" rel="noopener">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 2</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/" target="_blank" rel="noopener">MCU Friend 3.5" Identification</a></td>
</tr>
</tbody></table></div></p></span></p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/mcu-friend-3-5-tft-identification/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>PSoC 6 + Segger EmWin + MCUFriend 2.4&#8243; TFT &#8211; Part 2</title>
		<link>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/</link>
					<comments>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Wed, 28 Nov 2018 13:00:27 +0000</pubDate>
				<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6190</guid>

					<description><![CDATA[Summary In the previous Article (Part 1), I used an Arduino and two open source libraries to figure out the startup configuration sequence for a low cost 2.4&#8243; TFT from MCUFriend.  In Part 2, I will show you how to use that information to make a driver for a PSoC 6 running the Segger emWin [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>In the previous Article (<a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/" target="_blank" rel="noopener">Part 1</a>), I used an Arduino and two open source libraries to figure out the startup configuration sequence for a low cost 2.4&#8243; TFT from <a href="http://mcufriend.com" target="_blank" rel="noopener">MCUFriend</a>.  In Part 2, I will show you how to use that information to make a driver for a PSoC 6 running the <a href="https://www.segger.com/products/user-interface/emwin/" target="_blank" rel="noopener">Segger emWin</a> graphics library.</p>
<p>The steps that I will follow are:</p>
<ol>
<li>Create an Example project for the <a href="http://www.cypress.com/documentation/development-kitsboards/tft-display-shield-board-cy8ckit-028-tft" target="_blank" rel="noopener">CY8CKIT-028-TFT</a> from <a href="http://www.cypress.com/documentation/code-examples/ce223726-psoc-6-tft-display-interface-emwin-graphics-library" target="_blank" rel="noopener">CE223726</a> and test (make sure the emWin library works)</li>
<li>Copy the Example and Update Schematic and Pin Out for the MCUFriend Shield.</li>
<li>Modify the project and initialization code for the ILI9341</li>
<li>Test</li>
</ol>
<h1>Create an Example Project from CE223726 and Test</h1>
<p>Cypress has delivered a code example for the CY8CKIT-028-TFT shield called <a href="http://www.cypress.com/documentation/code-examples/ce223726-psoc-6-tft-display-interface-emwin-graphics-library">CE223726</a>.  This CE has all of the hardware connection setup for that shield, plus the integrated emWin middleware and a simple main that just displays 9 different screens.</p>
<p>The shield has a <a href="http://www.newhavendisplay.com/nhd24240320cfctxift-p-8177.html" target="_blank" rel="noopener">Newhaven 2.4&#8243; 320&#215;240 TFT</a> with a <a href="http://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf" target="_blank" rel="noopener">Sitronix ST7789</a> driver.  This display uses the &#8220;8080&#8221; interface for the display, the same parallel interface as my MCUFriend shield.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0016/" rel="attachment wp-att-6224"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0016-1024x999.jpg" alt="" width="1024" height="999" class="alignnone size-large wp-image-6224" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0016-1024x999.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0016-600x585.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0016-300x293.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0016-768x749.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>To run the code example, first create a new project from the File-&gt;Code Example menu.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-6-41-54-pm/" rel="attachment wp-att-6203"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.41.54-PM.png" alt="" width="640" height="206" class="alignnone size-full wp-image-6203" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.41.54-PM.png 640w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.41.54-PM-600x193.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.41.54-PM-300x97.png 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a></p>
<p>When you filter the list to &#8220;tft&#8221; by typing in the &#8220;Filter by&#8221; box you will see CE223726&#8230;. select it, then press &#8220;Create Project&#8221;.   If it is not on your computer you need to press the little world symbol to download it.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-5-34-33-pm/" rel="attachment wp-att-6198"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.33-PM.png" alt="" width="627" height="475" class="alignnone size-large wp-image-6198" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.33-PM.png 627w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.33-PM-600x455.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.33-PM-300x227.png 300w" sizes="auto, (max-width: 627px) 100vw, 627px" /></a></p>
<p>Accept the defaults for the Target IDE by pressing Next.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-5-34-51-pm/" rel="attachment wp-att-6197"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.51-PM.png" alt="" width="621" height="468" class="alignnone size-large wp-image-6197" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.51-PM.png 621w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.51-PM-600x452.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.34.51-PM-300x226.png 300w" sizes="auto, (max-width: 621px) 100vw, 621px" /></a></p>
<p>Give the project a sensible name, or accept the default name.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-5-35-07-pm/" rel="attachment wp-att-6196"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.35.07-PM.png" alt="" width="625" height="467" class="alignnone size-full wp-image-6196" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.35.07-PM.png 625w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.35.07-PM-600x448.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-5.35.07-PM-300x224.png 300w" sizes="auto, (max-width: 625px) 100vw, 625px" /></a></p>
<p>Once you have the project.  Program it to make sure that it works.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0012-2/" rel="attachment wp-att-6195"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0012-e1543099356162-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6195 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0012-e1543099356162-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0012-e1543099356162-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0012-e1543099356162-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0012-e1543099356162-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0013-2/" rel="attachment wp-att-6194"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0013-e1543099326359-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6194 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0013-e1543099326359-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0013-e1543099326359-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0013-e1543099326359-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0013-e1543099326359-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Copy the Example and Update Schematic and Pin Out</h1>
<p>Now that I have the code example project tested, I will make a copy of it to serve as a base for the mcufriend version.  In the workspace explorer, select the project then Copy it with ctrl-c.  Next, click on the workspace and Paste with ctrl-v.  Then, rename the project to &#8220;mcufriend&#8221;.  Here is the workspace explorer after the copy/paste/rename.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-7-09-57-pm/" rel="attachment wp-att-6209"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.09.57-PM.png" alt="" width="670" height="244" class="alignnone size-full wp-image-6209" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.09.57-PM.png 670w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.09.57-PM-600x219.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.09.57-PM-300x109.png 300w" sizes="auto, (max-width: 670px) 100vw, 670px" /></a></p>
<p>The schematic for this project is interesting.  These LCDs use what is called the 8080 interface.  It was named 8080 because it is the same 8-bit interface that the old 8080 CPUs used.  Instead of using a &#8220;bit-banged&#8221; interface (like the Arduino implementation) Cypress created a digital component that knows how to write to the screen.  Actually this is bad-ass.  You can see that the component has D0-D7, Data/Command (D/C), Chip Select, Write (nwr) and Read (NRD).  Inside of the block there is a FIFO and a timing circuit that will let you write 8-bits at a time to the screen.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-6-27-03-am/" rel="attachment wp-att-6226"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-6.27.03-AM.png" alt="" width="824" height="628" class="alignnone size-full wp-image-6226" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-6.27.03-AM.png 824w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-6.27.03-AM-600x457.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-6.27.03-AM-300x229.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-6.27.03-AM-768x585.png 768w" sizes="auto, (max-width: 824px) 100vw, 824px" /></a></p>
<p>Now on with modifying the project.  First, you notice that the 2.4&#8243; TFT shield has a different pin out than the CY8CKIT-028-TFT.  Here is a picture of the back of the shield:</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0018/" rel="attachment wp-att-6225"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0018-1024x794.jpg" alt="" width="1024" height="794" class="alignnone size-large wp-image-6225" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0018-1024x794.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0018-600x465.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0018-300x232.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0018-768x595.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>To sort this out I created this <a href="https://docs.google.com/spreadsheets/d/1FFkk0heJGKNlR7PK6_guteelkhOr2OK4ztinpwm2mrA/edit?usp=sharing" target="_blank" rel="noopener">pin map</a>.  The other thing to notice is that the pin called &#8220;LCD_RS&#8221; is really the &#8220;LCD_C/D&#8221; pin.  I am not sure why they called it &#8220;RS&#8221; (well my friend Rajesh figured it out&#8230; RS means Register Select).  Anyway, here is a picture of the spreadsheet.  Another interesting thing to notice is that Cypress choose not to include the Chip Select on the pinout of the shield and in fact it is always selected.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-6-48-31-pm/" rel="attachment wp-att-6207"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM-1024x655.png" alt="" width="1024" height="655" class="alignnone size-large wp-image-6207" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM-1024x655.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM-600x384.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM-300x192.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM-768x491.png 768w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.48.31-PM.png 1894w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>All right, you can see that the pins are different, so, the first step in fixing this project is to remap the pins to match the shield.  Open up the Design Wide Resource pin configuration screen from the Workspace Explorer.  And assign the Shield Pins to the correct PSoC 6 pins.  Notice that I added a UART (which you can ignore)</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-6-12-30-pm/" rel="attachment wp-att-6202"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.12.30-PM.png" alt="" width="610" height="411" class="alignnone size-full wp-image-6202" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.12.30-PM.png 610w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.12.30-PM-600x404.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-6.12.30-PM-300x202.png 300w" sizes="auto, (max-width: 610px) 100vw, 610px" /></a></p>
<p>The next thing that I need to do is update the schematic to reflect the ILI9341 speed.  On page 226 of the ILI9341 datasheet you can see that during a write cycle the write pulse needs to be low twrl=15ns and high twrh=15ns and the whole cycle needs to be at least 66ns.  For the read cycle the read pulse low trdl=45ns and the trdh=90ns.  Unfortunately, I dont know what an &#8220;FM&#8221; read is versus a &#8220;ID&#8221; read&#8230; so I am going to assume we only do &#8220;ID&#8221; reads.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-7-40-14-am/" rel="attachment wp-att-6230"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM-1024x735.png" alt="" width="1024" height="735" class="alignnone size-large wp-image-6230" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM-1024x735.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM-600x431.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM-300x215.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM-768x551.png 768w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-7.40.14-AM.png 1850w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>The input clock to the LCD Interface component sets the width of the output write pulse.  Specifically, the write output is always low for 1 clock cycle and high for 1 clock cycle.  For instance, if your clock is set to 10MHz (also known as a period 100ns) then your write output pulse will be 100ns (low) + 100ns(high).  For the read pulse you are given the ability to set the number of clocks for low and high.  In the above case of a 10MHz input clock if you set the low to 3 and the high to 5 you would end up with 3*100ns  (low) + 5*100ns (high) = 800ns total.</p>
<p>Armed with all of that information, we need to pick 3 numbers.  An input clock, the # of read low pulse and the # of read high pulses.  The write cycle needs to be at least 66ns so we need a minimum clock frequency of 30MHz which will have a period of 33ns.  For the read we need 45ns low and 90ns high and a total of 160ns.  This means the whole read cycle needs to be 160ns/33ns=4.8 clock cycles.  To achieve this ill select 2 low (for 66ns) and 3 high (99 ns) total 165ns.</p>
<p>Open the schematic, then double click the clock and change its frequency to 30MHz.  (notice that I renamed it to LCD_Clock)</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-14-23-am/" rel="attachment wp-att-6234"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.14.23-AM.png" alt="" width="630" height="482" class="alignnone size-large wp-image-6234" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.14.23-AM.png 630w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.14.23-AM-600x459.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.14.23-AM-300x230.png 300w" sizes="auto, (max-width: 630px) 100vw, 630px" /></a></p>
<p>Double click the GraphicLCDIntf to update the read transaction low pulse to have 2-clocks and the read transaction high pulse width to be 3-clocks.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-12-28-am/" rel="attachment wp-att-6232"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM-1024x717.png" alt="" width="1024" height="717" class="alignnone size-large wp-image-6232" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM-1024x717.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM-600x420.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM-300x210.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM-768x538.png 768w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.12.28-AM.png 1065w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>But wait.  Why is the pulse width 40ns and 80ns?  That means that the input clock is set to 25MHz (40ns period).  Well it turns out that is exactly right.  But if we typed in 30MHz how did we end up with 25MHz?  If you look on the clocks tab of the design wide resources you will find that the source of the LCD_Clock is the Clk_Peri and it is running at 50MHz.  When PSoC Creator figures out a clock, it can only choose a whole number divider, also known a 2 to synthesize the LCD_Clk, which means that the output frequency will actually be 25MHz.  I am pretty sure that I could move things around and figure out a combination of dividers and clock frequencies to make it work, but that isnt the point today so Ill just move forward.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-16-00-am/" rel="attachment wp-att-6233"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.16.00-AM.png" alt="" width="758" height="463" class="alignnone size-full wp-image-6233" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.16.00-AM.png 758w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.16.00-AM-600x366.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.16.00-AM-300x183.png 300w" sizes="auto, (max-width: 758px) 100vw, 758px" /></a></p>
<h1>Modify the Initialization Code</h1>
<p>With the schematic and pin out modified, we will turn our attention to the code.  There are several changes that need to be made to LCDConf.c</p>
<ol>
<li>Create a function called &#8220;_InitController_9341&#8221; to startup the screen (based on the learning from Part 1)</li>
<li>Change the name of function &#8220;_InitController&#8221; to be &#8220;_InitController_st7789&#8221;</li>
<li>Update the LCD_X_Config function with the correct orientation and color format</li>
<li>Update the function &#8220;LCD_X_DisplayDriver&#8221; to call the correct Initialization function</li>
</ol>
<p>In order to get the screen going, you need to send the commands/data that we discovered in Part 1.  The author of that code had a structure which I like for holding that data.  Specifically it is an array of uint8_ts with Command, Length of Data , Data 0-N and on and on.  This is exactly the format that I spit out from the Arduino code in the Part 1.  Here is the screenshot:</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-2-57-13-pm/" rel="attachment wp-att-6170"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM.png" alt="" width="819" height="891" class="alignnone size-full wp-image-6170" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM.png 819w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-600x653.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-276x300.png 276w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-768x836.png 768w" sizes="auto, (max-width: 819px) 100vw, 819px" /></a></p>
<p>To use this data I create an array (called ILI9341_regValues_2_4 &#8230; the same name from the original library.</p>
<pre class="start-line:103 lang:c decode:true">static const uint8_t ILI9341_regValues_2_4[]  = {        // BOE 2.4"                                                                                                                
0x1,0x0,                                  // Software Reset
0x28,0x0,                                 // Display Off
0x3A,0x1,0x55,                            // Pixel Format RGB=16-bits/pixel MCU=16-bits/Pixel
0xF6,0x3,0x1,0x1,0x0,                     // Interface control .. I have no idea
#if 0    
0xCF,0x3,0x0,0x81,0x30,                   // Not defined
0xED,0x4,0x64,0x3,0x12,0x81,              // Not defined
0xE8,0x3,0x85,0x10,0x78,                  // Not defined
0xCB,0x5,0x39,0x2C,0x0,0x34,0x2,          // Not defined
0xF7,0x1,0x20,                            // Not defined
0xEA,0x2,0x0,0x0,                         // Not defined  
    #endif
0xB0,0x1,0x0,                             // RGB Interface Control
0xB1,0x2,0x0,0x1B,                        // Frame Rate Control
0xB4,0x1,0x0,                             // Display Inversion Control
0xC0,0x1,0x21,                            // Power Control 1
0xC1,0x1,0x11,                            // Power Control 2
0xC5,0x2,0x3F,0x3C,                       // VCOM Control 1
0xC7,0x1,0xB5,                            // VCOM Control 2
0x36,0x1,0x48,                            // Memory Access Control

#if 0
0xF2,0x1,0x0,                             // Not defined
#endif

0x26,0x1,0x1,                             // Gamma Set
0xE0,0xF,0xF,0x26,0x24,0xB,0xE,0x9,0x54,0xA8,0x46,0xC,0x17,0x9,0xF,0x7,0x0,    // Positive Gamma Correction
0xE1,0xF,0x0,0x19,0x1B,0x4,0x10,0x7,0x2A,0x47,0x39,0x3,0x6,0x6,0x30,0x38,0xF,  // Negative Gamme Correction
0x11,0x0,                                 // Sleep Out
0x29,0x0,                                 // Display On
0x36,0x1,0x48,                            // Memory Access Control
0x2A,0x4,0x0,0x0,0x0,0xEF,                // Column Address Set = 239
0x2B,0x4,0x0,0x0,0x1,0x3F,                // Row Address Set  = 319
0x33,0x6,0x0,0x0,0x1,0x40,0x0,0x0,        // Vertical Scrolling Definition
0x37,0x2,0x0,0x0,                         // Vertical Scrolling Start Address
0x13,0x0,                                 // Normal Display ON
0x20,0x0,                                 // Display Inversion OFF
};


</pre>
<p>Notice that I have ifdef&#8217;d out the values that dont do anything.  In order to use the array, I create a function called _InitController_9341.  It</p>
<ol>
<li>Starts the component</li>
<li>Sends a reset</li>
<li>Then loops through the datastrcture from above sending Write Commands (GraphicLCDIntf_1_Write8_A0) and Write Data (GraphicLCDIntf_1_Write8_A1)</li>
</ol>
<pre class="lang:c decode:true">static void _InitController_9341(void)
{
    /* Start the parallel interface */
    GraphicLCDIntf_1_Start();

    /* Reset - High, Low (reset), High */
    Cy_GPIO_Set(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    GUI_Delay(20);
    Cy_GPIO_Clr(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    GUI_Delay(100);
    Cy_GPIO_Set(LCD_RESET_N_0_PORT, LCD_RESET_N_0_NUM);
    GUI_Delay(100);
    
    for(unsigned int i=0;i&lt;sizeof(ILI9341_regValues_2_4);i++)
    {
        GraphicLCDIntf_1_Write8_A0(ILI9341_regValues_2_4[i]);
        printf("Command %02X\r\n",ILI9341_regValues_2_4[i]);
        i=i+1;
        unsigned int count;
        count = ILI9341_regValues_2_4[i];
        for(unsigned int j=0;j&lt;count;j++)
        {
            i=i+1;
            printf("Data %02X\r\n",ILI9341_regValues_2_4[i]);
            GraphicLCDIntf_1_Write8_A1(ILI9341_regValues_2_4[i]);
        }
        
    }

}</pre>
<p>Now we move onto the configuration function.  There are several changes that need to be made to it.</p>
<ol>
<li>What driver chip you are using?</li>
<li>What is the bus interface you are going to use?</li>
<li>What is the format of the RGB Data?</li>
<li>How do you want the screen setup?</li>
</ol>
<p>The function call on line 319 configures the driver and the bus interface.</p>
<pre class="start-line:319 EnlighterJSRAW" data-enlighter-language="c" ">GUIDRV_FlexColor_SetFunc(pDevice, &amp;PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B8);</pre>
<p>The driver is specified from table 33.42 on page 1193 of the emWin manual.  Specifically, you tell it to use GUIDRV_FLEXCOLOR_F66709 which you can see support ILI9341 amongst others.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-39-01-am/" rel="attachment wp-att-6239"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.39.01-AM.png" alt="" width="689" height="170" class="alignnone size-full wp-image-6239" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.39.01-AM.png 689w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.39.01-AM-600x148.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.39.01-AM-300x74.png 300w" sizes="auto, (max-width: 689px) 100vw, 689px" /></a></p>
<p>Then you need to tell what bus interface to use.  When we setup the display, we told it that we wanted 16-bit color by sending 0x3A, 0x55.  Here is a screen shot from the ILI9341 datasheet.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-7-38-56-pm/" rel="attachment wp-att-6217"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.38.56-PM-1024x549.png" alt="" width="1024" height="549" class="alignnone size-large wp-image-6217" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.38.56-PM-1024x549.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.38.56-PM-600x322.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.38.56-PM-300x161.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.38.56-PM-768x412.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Given that, the last parameter of the driver call is the bus format.  So, set the bus width to 16 bits per pixel, 8-bit bus.</p>
<pre class="start-line:319 EnlighterJSRAW" data-enlighter-language="c"">GUIDRV_FlexColor_SetFunc(pDevice, &amp;PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B8);</pre>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-32-28-am/" rel="attachment wp-att-6237"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.32.28-AM.png" alt="" width="716" height="242" class="alignnone size-full wp-image-6237" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.32.28-AM.png 716w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.32.28-AM-600x203.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.32.28-AM-300x101.png 300w" sizes="auto, (max-width: 716px) 100vw, 716px" /></a></p>
<p>Now you need to tell it what bits mean what color.  For this display 16-bit color is encoded at 5-bits of Red, 6-bits of Green and 5-bits of Blue.  On Page 65 of the ILI9341 datasheet you can see that we should send 8-bits of command, 5 bits of red, 6-bits of green, 5-bits of blue, then the next pixel.</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-25-at-8-26-02-am/" rel="attachment wp-att-6236"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM-1024x388.png" alt="" width="1024" height="388" class="alignnone size-large wp-image-6236" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM-1024x388.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM-600x227.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM-300x114.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM-768x291.png 768w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-25-at-8.26.02-AM.png 1075w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>To tell emWin that, you need to pick GUICC_M565 (see the screen shot below from the Segger emWin documentation)</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-24-at-7-47-16-pm/" rel="attachment wp-att-6219"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM-1024x98.png" alt="" width="1024" height="98" class="alignnone size-large wp-image-6219" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM-1024x98.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM-600x58.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM-300x29.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM-768x74.png 768w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-7.47.16-PM.png 1272w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>But it turns out that doesnt work?  The blue and green are FLIPPED.  How is that possible?  As I tried to figure this out I googled a bunch of things&#8230; read on the Segger forums etc.  All of the normal things.  Finally I sent a note to some of my friends at Cypress that went like this:</p>
<p>&#8220;There are several possibilities</p>
<ol>
<li>There is a bug in emWin</li>
<li>There is a bug in the ILI9341</li>
<li>There is a bug in the emWin documentation</li>
<li>There is a bug in the ILI9341 documentation</li>
<li>There is a bug in my firmware</li>
<li>There is a bug in my brain.</li>
<li>There is a bug in my understanding of the documentation</li>
</ol>
<p>Personally I bet on #7&#8243;</p>
<p>Well it turned out that I was right.  It was #7.  The Red-Green-Blue order is set by register 36h</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/screen-shot-2018-11-26-at-7-53-41-am/" rel="attachment wp-att-6262"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-26-at-7.53.41-AM-1024x402.png" alt="" width="1024" height="402" class="alignnone size-large wp-image-6262" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-26-at-7.53.41-AM-1024x402.png 1024w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-26-at-7.53.41-AM-600x236.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-26-at-7.53.41-AM-300x118.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-26-at-7.53.41-AM-768x302.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>If you recall I copied setup from the Arduino code in Part 1.  When I called the setup I wrote 0x48 into that register&#8230; that is also known as BGR = 1 or &#8220;1=BGR color filter panel&#8221;.  It turns out that the example of the byte writing order above is just that&#8230; and example.  How did I figure this out?  Simple answer, thank you to Oleksandr in Ukraine for sorting that out for me because I was going out of my mind last night.</p>
<p>Now, the other little nasty part of things is that if I had written BGR=0 it still would not have worked.  It turns out that emWin overwrites that bit when it rotates the screen.  Why?  Who the hell knows.  Anyway, here is what Oleksandr says, &#8220;In your code in the initialization sequence you set 0x36 register to 0x48 so, BRG mode must be active and GUICC_565 palette must be correct.  But FlexColor driver itself writes to the 0x36 register in order to setup display orientation. By default, driver set the BRG bit to zero, activating RGB mode.&#8221;  Here is a rather vague description of what happens from the emWin documentation. <strong>[There is still an error here]</strong></p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/image007-2/" rel="attachment wp-att-6265"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/image007.png" alt="" width="669" height="260" class="alignnone size-full wp-image-6265" srcset="https://iotexpert.com/wp-content/uploads/2018/11/image007.png 669w, https://iotexpert.com/wp-content/uploads/2018/11/image007-600x233.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/image007-300x117.png 300w" sizes="auto, (max-width: 669px) 100vw, 669px" /></a></p>
<p>With the color order sorted out, the last thing that I change is the orientation of the display on line 309.  Here is the entire configuration function:</p>
<pre class="start-line:289 lang:c decode:true">void LCD_X_Config(void) {
    GUI_DEVICE * pDevice;
    CONFIG_FLEXCOLOR Config = {0};
    GUI_PORT_API PortAPI = {0};
    //
    // Set the display driver and color conversion
    //
    // GUICC_565
    // GUICC_M565
    pDevice = GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, GUICC_565, 0, 0);
    //
    // Display driver configuration
    //
    LCD_SetSizeEx    (0, XSIZE_PHYS,   YSIZE_PHYS);
    LCD_SetVSizeEx   (0, VXSIZE_PHYS,  VYSIZE_PHYS);
    //
    // Orientation
    //
    //Config.Orientation   = GUI_MIRROR_Y | GUI_SWAP_XY;
    Config.Orientation   = GUI_SWAP_XY;
    GUIDRV_FlexColor_Config(pDevice, &amp;Config);
    //
    // Set controller and operation mode
    //
    PortAPI.pfWrite8_A0  = GraphicLCDIntf_1_Write8_A0;
    PortAPI.pfWrite8_A1  = GraphicLCDIntf_1_Write8_A1;
    PortAPI.pfWriteM8_A1 = GraphicLCDIntf_1_WriteM8_A1;
    PortAPI.pfRead8_A1  = GraphicLCDIntf_1_Read8_A1;
    PortAPI.pfReadM8_A1  = GraphicLCDIntf_1_ReadM8_A1;
    GUIDRV_FlexColor_SetFunc(pDevice, &amp;PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B8);
}</pre>
<p>In the LCD_X_DisplayDriver function I will simply call the correct initialization function&#8230; the one we just created &#8230; called _InitController_9341</p>
<pre class="start-line:344 EnlighterJSRAW" data-enlighter-language="c"">int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {
    int r;

    GUI_USE_PARA(LayerIndex);
    GUI_USE_PARA(pData);

    switch (Cmd) {
        case LCD_X_INITCONTROLLER: {
            //
            // Called during the initialization process in order to set up the
            // display controller and put it into operation. If the display
            // controller is not initialized by any external routine, this needs
            // to be adapted by the customer...
            //
            // ...
            _InitController_9341();
            return 0;
        }
        default:
            r = -1;
    }
    return r;
}
</pre>
<h1>Test</h1>
<p>Finally a program and test&#8230; and lookey here&#8230; it works:</p>
<p><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0014/" rel="attachment wp-att-6199"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0014-e1543099810598-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6199 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0014-e1543099810598-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0014-e1543099810598-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0014-e1543099810598-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0014-e1543099810598-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a> <a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/img_0015/" rel="attachment wp-att-6200"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0015-e1543099839368-1024x768.jpg" alt="" width="1024" height="768" class="alignnone wp-image-6200 size-large" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0015-e1543099839368-1024x768.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0015-e1543099839368-600x450.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0015-e1543099839368-300x225.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0015-e1543099839368-768x576.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>You can find all of these projects on my github site: https://github.com/iotexpert/MCUFriend or clone it with git clone git@github.com:iotexpert/MCUFriend.git</p>
<p><span><h1>Embedded Graphics Index</h1>
<p><div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Embedded Graphics</th>
</tr>
</thead>
<tbody>
<tr><td >Embedded Graphics Overview</td>
</tr>

<tr><td >TFT Displays &amp; Drivers</td>
</tr>

<tr><td >TFT Controllers</td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 1</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/" target="_blank" rel="noopener">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 2</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/" target="_blank" rel="noopener">MCU Friend 3.5" Identification</a></td>
</tr>
</tbody></table></div></p></span></p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PSoC 6 + Segger EmWin + MCUFriend 2.4&#8243; TFT &#8211; Part 1</title>
		<link>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/</link>
					<comments>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/#respond</comments>
		
		<dc:creator><![CDATA[Alan Hawse]]></dc:creator>
		<pubDate>Mon, 26 Nov 2018 12:46:59 +0000</pubDate>
				<category><![CDATA[Graphics]]></category>
		<guid isPermaLink="false">https://iotexpert.com/?p=6166</guid>

					<description><![CDATA[Summary This article takes you through the steps that I went through to figure out the startup sequence for a 2.4&#8243; TFT MCUFriend display (Part 1), and then port it to a PSoC 6 running Segger emWin graphics library (Part 2) I recently tried out the Cypress CY8CKIT-028-TFT with the PSoC Creator Example Project, CE223726.  This [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Summary</h1>
<p>This article takes you through the steps that I went through to figure out the startup sequence for a 2.4&#8243; TFT MCUFriend display (Part 1), and then port it to a PSoC 6 running <a href="https://www.segger.com/products/user-interface/emwin/" target="_blank" rel="noopener">Segger emWin graphics library</a> (Part 2)</p>
<p>I recently tried out the Cypress CY8CKIT-028-TFT with the PSoC Creator Example Project, CE223726.  This code example builds a project using the Segger EmWin library, its pretty cool.  And, I have been interested in LCDs so I purchased some random LCD shields from eBay, including a rather generic looking 2.4&#8243; TFT from <a href="https://www.banggood.com/2_4-Inch-TFT-LCD-Shield-240320-Touch-Board-Display-Module-With-Touch-Pen-For-Arduino-UNO-p-1171082.html?gmcCountry=US&amp;currency=USD&amp;createTmp=1&amp;utm_source=googleshopping&amp;utm_medium=cpc_elc&amp;utm_content=frank&amp;utm_campaign=pla-ele-us-pc-1102&amp;gclid=CjwKCAiAiuTfBRAaEiwA4itUqMmQbIRcvVKutBzDgShpM0C5Q8Mdv1pWgGFVn1TE18mvWH_LIReY0xoCPSMQAvD_BwE&amp;cur_warehouse=CN">bang good</a> (a generic Chinese reseller).  The entirety of the documentation is silkscreen plus the sticker you see in the picture, which just tells you that it has an ILI9341 LCD driver.</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/img_0011-2/" rel="attachment wp-att-6184"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0011-1024x797.jpg" alt="" width="1024" height="797" class="alignnone size-large wp-image-6184" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0011-1024x797.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0011-600x467.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0011-300x234.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0011-768x598.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a>  <a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/img_0007/" rel="attachment wp-att-6186"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0007-1024x701.jpg" alt="" width="1024" height="701" class="alignnone size-large wp-image-6186" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0007-1024x701.jpg 1024w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0007-600x410.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0007-300x205.jpg 300w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0007-768x525.jpg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></p>
<p>This left me with a number of questions  Starting with, How do you initialize the screen?  Obviously you can find the <a href="https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf" target="_blank" rel="noopener">Ilitech ILI9341 datasheet</a>, but then what?  The datasheet has fifty billion parameters, and not much advice about what to do.  Moreover, after googling around, I discovered that there is an absolute rogues gallery of bad advice about these screens.  Horrible horrible.  Finally, I found an Arduino library called &#8220;MCUFRIEND_kbv&#8221; that seemed like it was coherent.  So, I installed it and got the screen working &#8211; just to prove that it worked.  But I&#8217;m still not going to use an Arduino, so I need to port the initialization to my Segger emWin project.</p>
<p>Here is what I did to sort this out:<a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/img_0006-4/" rel="attachment wp-att-6187"></a></p>
<ol>
<li>Install the Arduino libraries to use the 2.4&#8243; TFT MCUFriend Shield</li>
<li>Fix &amp; Run the Arduino Example project to prove that it works</li>
<li>Modify the MCUFRIEND_kbv.c to dump the ILI9341 Startup sequence</li>
<li>Verify the startup sequence against the ILI9341 data sheet (and fix the errors)</li>
<li>Modify the CE223726 to use the ILI9341 shield</li>
</ol>
<h1>Install the Arduino Libraries</h1>
<p>In order to use the screen I need the Arduino libraries that drive it.  Start by installing the Adafruit GFX library select Sketch&#8211;&gt;Include Library&#8211;&gt;Manage Libraries&#8230;</p>
<p><a href="https://iotexpert.com/?attachment_id=6180" rel="attachment wp-att-6180"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.07.53-PM.png" alt="" width="658" height="329" class="alignnone size-full wp-image-6180" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.07.53-PM.png 658w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.07.53-PM-600x300.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.07.53-PM-300x150.png 300w" sizes="auto, (max-width: 658px) 100vw, 658px" /></a></p>
<p>In the filter box type &#8220;gfx&#8221;.  Once you find the Adafruit GFX Library, you can click Install.</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-11-19-pm/" rel="attachment wp-att-6178"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.19-PM.png" alt="" width="801" height="451" class="alignnone size-large wp-image-6178" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.19-PM.png 801w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.19-PM-600x338.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.19-PM-300x169.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.19-PM-768x432.png 768w" sizes="auto, (max-width: 801px) 100vw, 801px" /></a></p>
<p>Then you need to install mcufriend_kbv library.  Type &#8220;mcuf&#8221; into the filter.  Then select install.</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-11-40-pm/" rel="attachment wp-att-6177"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.40-PM.png" alt="" width="803" height="452" class="alignnone size-large wp-image-6177" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.40-PM.png 803w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.40-PM-600x338.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.40-PM-300x169.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.11.40-PM-768x432.png 768w" sizes="auto, (max-width: 803px) 100vw, 803px" /></a></p>
<p>These two operations will add the directories to your library:</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-23-53-pm/" rel="attachment wp-att-6181"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.23.53-PM.png" alt="" width="791" height="340" class="alignnone size-full wp-image-6181" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.23.53-PM.png 791w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.23.53-PM-600x258.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.23.53-PM-300x129.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.23.53-PM-768x330.png 768w" sizes="auto, (max-width: 791px) 100vw, 791px" /></a></p>
<h1>Fix &amp; Run the Arduino Example project</h1>
<p>After you have added the Libraries, you can then make a project based on one of the MCUFriend existing examples.  For this test case Ill pick File&#8211;&gt;Examples&#8211;&gt;MCUFRIEND_kbv&#8211;&gt;diagnose_TFT_support</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-12-29-pm-2/" rel="attachment wp-att-6179"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.12.29-PM-1.png" alt="" width="723" height="735" class="alignnone size-full wp-image-6179" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.12.29-PM-1.png 723w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.12.29-PM-1-600x610.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.12.29-PM-1-295x300.png 295w" sizes="auto, (max-width: 723px) 100vw, 723px" /></a></p>
<p>For this project to run you need to include the AdafruitGFX library. To do that select Sketch&#8211;&gt;Include Library&#8211;&gt;Adafruit GFX Library</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-13-17-pm/" rel="attachment wp-att-6175"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.17-PM.png" alt="" width="672" height="707" class="alignnone size-large wp-image-6175" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.17-PM.png 672w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.17-PM-600x631.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.17-PM-285x300.png 285w" sizes="auto, (max-width: 672px) 100vw, 672px" /></a></p>
<p>And also the SPI library with Sketch&#8211;&gt;Include Library&#8211;&gt;SPI</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-13-41-pm/" rel="attachment wp-att-6174"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.41-PM.png" alt="" width="659" height="445" class="alignnone size-large wp-image-6174" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.41-PM.png 659w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.41-PM-600x405.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.13.41-PM-300x203.png 300w" sizes="auto, (max-width: 659px) 100vw, 659px" /></a></p>
<p>Once that is done you can click on the build checkmark, then the download button and your screen should look something like this:</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-3-14-13-pm/" rel="attachment wp-att-6173"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.14.13-PM.png" alt="" width="855" height="775" class="alignnone size-full wp-image-6173" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.14.13-PM.png 855w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.14.13-PM-600x544.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.14.13-PM-300x272.png 300w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-3.14.13-PM-768x696.png 768w" sizes="auto, (max-width: 855px) 100vw, 855px" /></a></p>
<p>And you should have this:</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/img_0006-3/" rel="attachment wp-att-6171"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0006-768x1024.jpg" alt="" width="768" height="1024" class="alignnone size-large wp-image-6171" srcset="https://iotexpert.com/wp-content/uploads/2018/11/IMG_0006-768x1024.jpg 768w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0006-600x800.jpg 600w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0006-225x300.jpg 225w, https://iotexpert.com/wp-content/uploads/2018/11/IMG_0006-scaled.jpg 1920w" sizes="auto, (max-width: 768px) 100vw, 768px" /></a></p>
<p>And if you start the serial port monitor you will get this:</p>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-4-44-42-pm/" rel="attachment wp-att-6183"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-4.44.42-PM.png" alt="" width="573" height="465" class="alignnone size-full wp-image-6183" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-4.44.42-PM.png 573w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-4.44.42-PM-300x243.png 300w" sizes="auto, (max-width: 573px) 100vw, 573px" /></a></p>
<p>OK.  This is good.  This means that the screen is functioning and the Arduino library properly identifies it as a ILI9341.</p>
<h1>Modify the MCUFRIEND_kbv.cpp</h1>
<p>In order to get one of these screens going you need to set a bunch of parameters before you can attach it to your Graphics library.  But, what is the sequence.  I first started looking through the code&#8230;. but honestly it is a mess.  Here is a little snip of it:</p>
<pre class="lang:c++ decode:true ">case 0x9341:
      common_9341:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t ILI9341_regValues_2_4[] PROGMEM = {        // BOE 2.4"                                                                                                                
            0xF6, 3, 0x01, 0x01, 0x00,  //Interface Control needs EXTC=1 MV_EOR=0, TM=0, RIM=0                                                                                                     
            0xCF, 3, 0x00, 0x81, 0x30,  //Power Control B [00 81 30]                                                                                                                               
            0xED, 4, 0x64, 0x03, 0x12, 0x81,    //Power On Seq [55 01 23 01]                                                                                                                       
            0xE8, 3, 0x85, 0x10, 0x78,  //Driver Timing A [04 11 7A]                                                                                                                               
            0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,      //Power Control A [39 2C 00 34 02]                                                                                                         
            0xF7, 1, 0x20,      //Pump Ratio [10]                                                                                                                                                  
            0xEA, 2, 0x00, 0x00,        //Driver Timing B [66 00]                                                                                                                                  
            0xB0, 1, 0x00,      //RGB Signal [00]                                                                                                                                                  
            0xB1, 2, 0x00, 0x1B,        //Frame Control [00 1B]                                                                                                                                    
            //            0xB6, 2, 0x0A, 0xA2, 0x27, //Display Function [0A 82 27 XX]    .kbv SS=1                                                                                                 
            0xB4, 1, 0x00,      //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1                                                                                                                  
            0xC0, 1, 0x21,      //Power Control 1 [26]                                                                                                                                             
            0xC1, 1, 0x11,      //Power Control 2 [00]                                                                                                                                             
            0xC5, 2, 0x3F, 0x3C,        //VCOM 1 [31 3C]                                                                                                                                           
            0xC7, 1, 0xB5,      //VCOM 2 [C0]                                                                                                                                                      
            0x36, 1, 0x48,      //Memory Access [00]                                                                                                                                               
            0xF2, 1, 0x00,      //Enable 3G [02]                                                                                                                                                   
            0x26, 1, 0x01,      //Gamma Set [01]                                                                                                                                                   
            0xE0, 15, 0x0f, 0x26, 0x24, 0x0b, 0x0e, 0x09, 0x54, 0xa8, 0x46, 0x0c, 0x17, 0x09, 0x0f, 0x07, 0x00,
            0xE1, 15, 0x00, 0x19, 0x1b, 0x04, 0x10, 0x07, 0x2a, 0x47, 0x39, 0x03, 0x06, 0x06, 0x30, 0x38, 0x0f,
        };
</pre>
<p>Rather than try to figure out all of the stuff that I &#8220;THINK&#8221; that it sends, I decided to modify the WriteCmdParamN method to just print out what it actually sends.  And I decided to print it out in a format that would be easy to import into my program:  You can see that each time a command is sent, I print out the command number, followed by the number of bytes, followed by the actual bytes (this is similar to the original code).</p>
<pre class="lang:c++ decode:true">#define ARH_DEBUG

void MCUFRIEND_kbv::WriteCmdData(uint16_t cmd, uint16_t dat) { writecmddata(cmd, dat); }

static void WriteCmdParamN(uint16_t cmd, int8_t N, uint8_t * block)
{
#ifdef ARH_DEBUG
  Serial.print(F("0x"));
  Serial.print(cmd,HEX);
    Serial.print(F(",0x"));
    Serial.print(N,HEX);
    Serial.print(F(","));
#endif

    CS_ACTIVE;
    WriteCmd(cmd);
    while (N-- &gt; 0) {
        uint8_t u8 = *block++;
#ifdef ARH_DEBUG
  Serial.print(F("0x"));
    Serial.print(u8,HEX);
    Serial.print(F(","));
#endif
        write8(u8);
        if (N &amp;&amp; is8347) {
            cmd++;
            WriteCmd(cmd);
        }
    }
#ifdef ARH_DEBUG
    Serial.println(F(" "));
#endif
    CS_IDLE;
}
</pre>
<p>When I download and run the program you can see that it</p>
<ol>
<li>Issues a reset</li>
<li>Then sends the commands/data to configure the screen</li>
</ol>
<p><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/screen-shot-2018-11-24-at-2-57-13-pm/" rel="attachment wp-att-6170"><img loading="lazy" decoding="async" src="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM.png" alt="" width="819" height="891" class="alignnone size-full wp-image-6170" srcset="https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM.png 819w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-600x653.png 600w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-276x300.png 276w, https://iotexpert.com/wp-content/uploads/2018/11/Screen-Shot-2018-11-24-at-2.57.13-PM-768x836.png 768w" sizes="auto, (max-width: 819px) 100vw, 819px" /></a></p>
<p>OK thats good.  Now, the bad part, when I look at the commands in the ILI9341 documentation it turns out that 0xCF, 0xED, 0xE8, 0xCB, 0xF8, 0xEA and 0xF2 are not actually commands.  Hmmm&#8230; I suppose that they don&#8217;t do any harm?  But they also don&#8217;t appear to actually do anything.  I guess beggars can&#8217;t be choosers, so I won&#8217;t be critical.</p>
<p>In the next Article I&#8217;ll show you how to take this startup code and put it into a PSoC with Segger emWin.</p>
<p><span><h1>Embedded Graphics Index</h1>
<p><div class="table-responsive"><table  style="width:95%; "  class="easy-table easy-table-default " border="1">
<thead>
<tr><th >Embedded Graphics</th>
</tr>
</thead>
<tbody>
<tr><td >Embedded Graphics Overview</td>
</tr>

<tr><td >TFT Displays &amp; Drivers</td>
</tr>

<tr><td >TFT Controllers</td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/26/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 1</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/11/28/psoc-6-segger-emwin-mcufriend-2-4-tft-part-2/" target="_blank" rel="noopener">PSoC 6 + Segger EmWin + MCUFriend 2.4" TFT - Part 2</a></td>
</tr>

<tr><td ><a href="https://iotexpert.com/2018/12/04/mcu-friend-3-5-tft-identification/" target="_blank" rel="noopener">MCU Friend 3.5" Identification</a></td>
</tr>
</tbody></table></div></p></span></p>
]]></content:encoded>
					
					<wfw:commentRss>https://iotexpert.com/psoc-6-segger-emwin-mcufriend-2-4-tft-part-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
