Writing to E-Ink display over UART

send_begin() expects the display to send a letter c but as it seems you don't get that and hence your code is stuck in the while(1) hence I would add a timeout for that like this

const uint32_t TIMEOUT = 3000; // 3 seconds timeout

bool send_begin() {   
                                                   // spin the loop till broken or the timeout hits 
  for (uint32_t ms = millis(); millis() - ms < TIMEOUT; Particle.process()) {
    if (Serial1.read() == 'c') 
      break;
  }
                                                   // don't care whether we actually got a 'c' response or not 
  Serial1.write('a');                              // send "listen for transfer" command
                                                   // spin the loop till broken or the timeout hits 
  for (uint32_t ms = millis(); millis() - ms < TIMEOUT; Particle.process()) {
    if (Serial1.read() == 'b') 
      return true;                                 // expected response from display received
  }
  return false;                                    // second loop ran into the timeout, so no success
}

void setup() {
    Serial1.begin(230400);
    while (!send_begin()) 
      Particle.publish("Status ePaper", "begin failed", PRIVATE);

    Particle.publish("Status e-Paper", "testing", PRIVATE);
    write_image_picture();
}

(I also replaced all instances of SERIAL with Serial1)

You can also remove #include <wire.h> as it's neither required in the code nor needed with Particle. And with all the pgm stuff removed you don't need Arduino.h either.

What a horribly documented display! There is no documentation on the commands supported by the onboard STM32 and I find it odd that unit works by sending a c at some undefined interval to indicate it is ready to accept a command. In addition, Seeedstudio hints at the availability of code for the STM32 but doesn't provide a link and it is not in their repository:

If you need to change the startup code, check out the library's code for STM32

If possible, I suggest you first try using this thing on an Arduino board.

2 Likes

I agree with @peekay123 100% documentation for this display is terrible.
Maybe is a stupid question as this should be simple and obvious but could you share with us how did you wired-up Argon with this display ?
On seeedstudio website is some info that the display can be powered from 3.3V to 5V so I just wondering how is the level voltage on display UART if is powered from 5V ? please note that Argon UART is 3.3V and is not 5V tolerant

@dreamER, the display has level translators so 3.3v is safe as power and on GPIO. And I assume that from @tobiasv’s description, he is using the UART port (with RX and TX pins) on a Particle Feather Grove shield so the wiring should be fine. What I’m not sure about is the 230400 baud on Serial1.

If it were me, I would connect a USB-to-UART (FTDI) to my PC and connect to it using a terminal program like PuTTY and set it for 230Kbaud. I would make sure the jumper on the FTDI is set for 3.3v logic and then I would connect that to the Seria1 of the Argon. I could then “emulate” the display by sending a ‘c’ to the Argon and seeing how it responds.

I have not tested 230400 explicitly but I have a DMX-Project on Gen2 and Gen3 which uses 250000 on Serial1 just fine.
However, testing it would be a good idea.

I tested at 230Kbaud as I had described above (with FTDI on PC) and used the original code. @ScruffR, your wait logic isn’t quite right and causes the code to put out an ‘a’ every 3000ms which it shouldn’t. Just need some FSM code. However, with the original “wait forever” code, everything works as it should. So the problem may be:

  1. The display is not connected to the correct grove breakout connector (UART)
  2. The Argon is not mounted correctly in the Grove shield
  3. The display is not working as advertised
  4. There is damage to the Serial1 RX/TX pins caused previously (no likely)

I'm not sure you understood what my intent was and I would have expected it to emit an 'a' every six seconds when the display is not communicating as expected.

  1. wait up to 3 seconds for the initial 'c' but move on when not received
  2. send the 'a' to initiate conversation
  3. wait up to 3 seconds for the expected 'b' response
  4. when 'b' is received return true immediately otherwise false after 3 seconds

Once the display does respond with a 'b' the cycle should be broken as the while(!send_begin()) will be satisfied to leave by the returned true.
I admit I have not tested this but I wouldn't see why my code would behave any differently than that.

However, if you don't want the repeated attempt to connect to the display you would just not wrap the send_begin() call in that while() loop :wink:


Update:
@peekay123, since I rather doubt myself than others and listen to honest criticism I went on to test my code now and lo and behold it does behave as I intended it to do :wink:


It only keeps sending 'a' every six seconds not three and once the display responds with a 'b' after receiving an 'a' the cycle is broken and the image is sent out.

I tested with this code on an Argon

#include "Particle.h"

SYSTEM_THREAD(ENABLED);

const unsigned char IMAGE_BLACK[] = { /* 0X00,0X01,0XC8,0X00,0XC8,0X00, */
    0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
...
    0XFF, 0XFF, 0XFF, 0XFF,
};

const unsigned char IMAGE_RED[] = { /* 0X00,0X01,0XC8,0X00,0XC8,0X00, */
    0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
...
    0XFF, 0XFF, 0XFF, 0XFF,
};

#define RECV_ERROR       -1
#define CONTINUE_TRANS    0
#define RECV_DONE         1


//Send data to e-link board.
void serial_send_data(const uint8_t* data, uint32_t data_len) {
    for (int i = 0; i < data_len; i++) {
        Serial1.write(data[i]);
    }
}

//Send image array
void write_image_picture(void) {
    for (int i = 0; i < 13; i++) {
        serial_send_data(&IMAGE_BLACK[0 + i * 212], 212);
        delay(80);
    }
    delay(90);
    for (int i = 0; i < 13; i++) {
        serial_send_data(&IMAGE_RED[0 + i * 212], 212);
        delay(80);
    }
}

const uint32_t TIMEOUT = 3000; // 3 seconds timeout

bool send_begin() {   
                                                   // spin the loop till broken or the timeout hits 
  for (uint32_t ms = millis(); millis() - ms < TIMEOUT; Particle.process()) {
    if (Serial1.read() == 'c') 
      break;
  }
                                                   // don't care whether we actually got a 'c' response or not 
  Serial1.write('a');                              // send "listen for transfer" command
                                                   // spin the loop till broken or the timeout hits 
  for (uint32_t ms = millis(); millis() - ms < TIMEOUT; Particle.process()) {
    if (Serial1.read() == 'b') 
      return true;                                 // expected response from display received
  }
  return false;                                    // second loop ran into the timeout, so no success
}

void setup() {
    Serial1.begin(230400);
    while (!send_begin()) 
      Particle.publish("Status ePaper", "begin failed", PRIVATE);

    Particle.publish("Status e-Paper", "testing", PRIVATE);
    write_image_picture();
}

And a simple serial pass-through sketch on a Photon

SYSTEM_MODE(MANUAL)

void setup() {
    Serial.begin();
    Serial1.begin(230400);
    while(Serial.read()  >= 0);                         // flush Serial  input buffer
    while(Serial1.read() >= 0);                         // flush Serial1 input buffer
}

void loop() {
    while(true) {
      if (Serial.available()) Serial1.write(Serial.read());
      if (Serial1.available()) Serial.write(Serial1.read());
    }
}

@ScruffR, to be honest I didn’t time things before writing 3 secs! However, my understanding of this (stupid) interface is that you wait for a ‘c’, respond with an ‘a’ and wait for a ‘b’ before sending the image data. I don’t believe sending ‘a’ to get a response is what the “protocol” (said VERY loosely) calls for. Logically, you would think that some grade school programmer would have come up with the a-b-c sequence but instead they seem to have followed a much more logical (NOT) c-a-b sequence. :roll_eyes:

1 Like

My thought behind the timeout was that the 'c' might have been missed during the cloud connection (prior to adding SYSTEM_THREAD(ENABLED) for speedier startup) and the display may not resend it.
With neither a test unit nor some useful documentation lots of things may be assumed but the proof is in the pudding :wink:

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.