5 years, 8 months ago.

How to know when a command is completed?

Hello!

I'm new to this library, and I've dug into the code but didn't see if this was a bug, or a feature.

Hardware: FRDM-K64F, using the SPI interface that is intended for the wireless module Display: 800x480 OS: mbed OS 5

Scenario: I'm drawing two circles at the center of the screen, the first has 100 diameter, and the second is smaller at 50 diameter.

What happens? - the first circle gets only partially drawn. The second circle is fully drawn. If I add a delay between the two circles, (about 10msec delay) then they both get fully drawn. With a lower delay, a proportion of the first circle gets drawn. I guess the controller is busy still drawing the first circle, when the second command comes in. I'm fine with that, I don't mind inserting delays in between each command, but how do I know when a command has completed? Is there a callback, or some polling function I should execute? My apologies if this is something obvious - I have missed it : (

Many thanks!

Question relating to:

2 Answers

5 years, 8 months ago.

Hi Shabaz,

Are you using RA8875::circle() API? (from https://os.mbed.com/users/WiredHome/code/RA8875/file/ad2450fc3dc3/RA8875.cpp/ - RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit))?

From the code, it seems like the function returns a return code. I see that sample code given here https://os.mbed.com/users/WiredHome/code/RA8875_Demo/file/c8ef96a6e43b/RA8875.lib/ is not checking the return code and you may have done the same.

Please see if checking the return code from the API that you are using helps you.

Please let us know if you have any further questions.

Thanks, Naveen, team mbed.

Hi Naveen!

Thanks for the fast response! You're correct, I'm using that API. I have checked the return code, and it is "noerror". Here is my code snippet:

my code

    RetCode_t retcode;
    point_t p;
    
    p.x=400;
    p.y=240;
    
    lcd.foreground(RGB(255,255,0));

 

    lcd.SelectUserFont(BPG_Arial63x63);
    lcd.puts(10,10,"Boo!");


    retcode=lcd.circle(p, 100, BrightRed);
    //wait_us(11000);
    if (retcode==noerror)
    {
      retcode=lcd.circle(p, 50, BrightRed);
    }
    if (retcode!=noerror)
    {
        lcd.puts(10,30, "Error");
    }
    else
    {
        lcd.puts(10,30, "No error");
    }
    

When I run the code, I see the text "No error", but the large circle is only partially drawn (just a small part of it at the top of the circle). If I uncomment the wait_us line in the code above, then the circles are drawn fully complete, and I still see "No error" message. If I change the wait_us value to something less than 11000, for example 5000, then I see more of the large circle drawn compared to when the wait_us is fully commented out, but for it to be a full circle I need about 10msec (10000) to be used or higher.

I actually don't mind that the command completes before the circle is drawn. It gives the rest of my code more time to execute : ) But I have no way of knowing how long I should wait for, before issuing the next circle command. This is why I thought maybe there was some function I was supposed to call to check if the display is busy or something : ( Thanks,

Shabaz.

posted by Shabaz Yousaf 21 Aug 2018

Hi Shabaz,

Please see if you can use the features provided in STSR register on RA8875.

https://cdn-shop.adafruit.com/datasheets/RA8875_DS_V19_Eng.pdf

The RA8875 library uses this register in method like _WaitWhileBusy() . https://os.mbed.com/users/WiredHome/code/RA8875_Demo/ doesn't use any callbacks. RA8875 class also sets the callbacks to NULL, hence it seems like callbacks are not really used.

Thanks, Naveen, team Mbed.

posted by Naveen Kaje 21 Aug 2018
5 years, 7 months ago.

Hi Shabaz, I'm the author, so happy to jump in on this. And Naveen, thanks for jumping in as well.

In the circle method, as in most of the methods in this library, the return value primarily indicates if you created a bad command - as you see there are a few parameter checks to return a bad value error.

RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit)
{
    RetCode_t ret = noerror;

    PERFORMANCE_RESET;
    if (radius <= 0 || (x - radius) < 0 || (x + radius) > screenwidth 
    || (y - radius) < 0 || (y + radius) > screenheight) {
        ret = bad_parameter;
    } else if (radius == 1) {
        pixel(x,y);
    } else {
        WriteCommandW(0x99, x);
        WriteCommandW(0x9B, y);
        WriteCommand(0x9d, radius & 0xFF);
        unsigned char drawCmd = 0x00;       // Circle
        if (fillit == FILL)
            drawCmd |= 0x20;
        WriteCommand(0x90, drawCmd);
        WriteCommand(0x90, 0x40 + drawCmd); // Start drawing.
        if (!_WaitWhileReg(0x90, 0x40)) {
            REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
            return external_abort;
        }
    }
    REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
    return ret;
}

If it reaches the middle of that method, it writes the commands to the display, and then it has a call to _WaitWhileReg(), which should wait while it is busy drawing the circle.. Let's go look at that method.

So, the comment at the top might be a bit misleading - "add a timeout", when there clearly is some form of a timeout. But with that comment, I'd say there could be a bit of less that ideal behavior.

In any case, there is a while loop that is gated with ReadCommand() & mask. If it times out, it should then return a failure code, and if the command completes (as indicated by the ReadCommand() & mask) then it returns success.

/// @todo add a timeout and return false, but how long
/// to wait since some operations can be very long.
bool RA8875::_WaitWhileReg(uint8_t reg, uint8_t mask)
{
    int i = 20000/POLLWAITuSec; // 20 msec max

    while (i-- && ReadCommand(reg) & mask) {
        wait_us(POLLWAITuSec);
        COUNTIDLETIME(POLLWAITuSec);
        if (idle_callback) {
            if (external_abort == (*idle_callback)(command_wait, 0)) {
                return false;
            }
        }
    }
    if (i)
        return true;
    else
        return false;
}

Geographically in the code, the _WaitWhileReg is near a _WaitWhileBusy, the latter of which checks the STSR register. I don't have time to look at the datasheet right now, so this would be a good point to study. Perhaps I implemented the wait on the wrong register set...

So, I certainly won't rule out the possibility that there is an error in there, but I haven't seen what you describe in my own projects. Each command initiates the action in the display and then waits for its completion, or returns a code that something went wrong.

Unfortunately, I'm away from my own boards for a few days, so can't take your demo and try it (and I have only the LPC1768 in case that is somehow a factor). I don't think this will be a factor, but as a super quick and simple test, you might try slowing the SPI rate and try again - if you overclock the interface - and depending in part on your wiring, the SPI signals could be distorted and not so reliable.

When I get my hands on my own units, I'll give your demo a go.

Oh, and while these methods haven't changed in a long time, are you on the latest library?

I ran a test starting with your code. My full main.cpp is shown here, using the online compiler and with an LPC1768. Note the revision numbers of the mbed-os and RA8875 library.

//
#include "mbed.h"           // mbed-os rev 4464
#include "RA8875.h"         // rev 154
#include "BPG_Arial63x63.h"

#define LCD_W 480           // Configured for 4 in screen
#define LCD_H 272
#define LCD_C 16
RA8875 lcd(p5, p6, p7, p12, NC, "tft");             //MOSI, MISO, SCK, /ChipSelect, /reset, name
LocalFileSystem local("local");                     // access to file system for printscreen
DigitalOut led1(LED1);

int main()
{
    RetCode_t retcode;
    point_t p = {350, 150};

    lcd.init(LCD_W, LCD_H, LCD_C);
    lcd.Backlight(0.5f);
    lcd.foreground(RGB(255,255,0));
    lcd.SelectUserFont(BPG_Arial63x63);
    lcd.puts(10,10,"Boo!");
    retcode=lcd.circle(p, 100, BrightRed);
    //wait_us(11000);
    if (retcode==noerror) {
        retcode=lcd.circle(p, 50, BrightRed);
    }
    lcd.SetTextCursor(10,80);
    if (retcode!=noerror) {
        lcd.printf("Error %s", lcd.GetErrorMessage(retcode));
    } else {
        lcd.puts("no Error");
    }
    retcode = lcd.PrintScreen(0,0,LCD_W,LCD_H,"/local/Circle.bmp");
    lcd.SetTextCursor(10,160);
    lcd.printf("BMP %d", retcode);
    while (true) {
        led1 = !led1;
        wait(0.5);
    }
}

Before I added the PrintScreen, I rebooted over and over, maybe 2 dozen times and I did not see what you reported. I am using a 480x272 display for this test, but it has the same controller.

/media/uploads/WiredHome/circle.png

Since the display is write-mostly, I wonder if your SPI - MISO pin is not connected. I don't think it would work at all w/o that, but perhaps...

If you think the MISO pin is properly connected, perhaps you need a a pull-up resistor on that pin.

Shabaz, if this helps you solve it, please accept the answer. If not, tell us more.

posted by David Smart 23 Aug 2018

Hi David,

Thanks for invesigating! I accidentally missed seeing it earlier. I did test the commands to ensure I got back noerror, and also changed the SPI speed in case it was an issue there, and the SPI lines were about 6 incles long (unfortunately I couldn't make them shorter). I did check your code and compare to the datasheet, and to be honest I couldn't see what could be going wrong (like you, I suspected MISO issues but couldn't see how that could cause just that failure), so for now I've deliberately inserted short delays, and I'm hoping to retest after I've purchased a new display. The one I had used was intended for 5V operation, and I'd done the resistor surgery to get it to 3.3V, I'm confident I did that correctly, but there's no guarantee there wasn't an issue with the display - I couldn't get the resistive touch working, so there may well be issues with the single unit I have, so I'd like to purchase a new display to rule that out, and also with a hardware font chip so I can explore that. I also plan to have more accessible wiring to an oscilloscope so that I can more deeply explore with. Thanks again for responding, and also for your hard work creating the code - it really is excellent. I'll set your answer to 'accepted' if that is fine by you, and re-open if I can (or create a new question) if things don't work out with the new display.

posted by Shabaz Yousaf 26 Sep 2018