board707 / DMD_STM32

STM32Duino library for RGB, Monochrome and Two-color led matrix panels
GNU General Public License v3.0
54 stars 18 forks source link

Sending matrix include values of image in format RGB565 via FTDI to receive through USART1 in STM32F411CEU6 #101

Closed ZOUALFIKAR closed 1 month ago

ZOUALFIKAR commented 2 months ago

Panel description

Dimensions (in pixels) : 64x32 (3 panels ==> 96x64)

Scan factor: 1/8

Describe the problem:

i send a matrix value which data length 0x3000 = 6144 pixels = (packet 12288 bytes) from PC every 1 second via FTDI that use USART1 in STM32F411CEU6, baud rate =1000000, and when i sent the packet the serial was stuck after receive 1 or 2 packet, and if i remove this commands :

Specifications

THIS IS THE CODE:

#include "DMD_RGB.h"

int data_len;
int firstByte ;
int secondByte ;
int thirdByte ;
int fourthByte;
int thirdByte1;
int fourthByte1;
int rlen;
int BUFFER_SIZE;
int i =0;
uint16_t Image_buffer[7000];

#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 3
#define ENABLE_DUAL_BUFFER false

#if (defined(__STM32F1__) || defined(__STM32F4__))
// ==== DMD_RGB pins ====
// mux pins - A, B, C... all mux pins must be selected from same port!
#define DMD_PIN_A PB6
#define DMD_PIN_B PB5
#define DMD_PIN_C PB4
#define DMD_PIN_D PB3
#define DMD_PIN_E PB8
// put all mux pins at list
uint8_t mux_list[] = { DMD_PIN_A , DMD_PIN_B , DMD_PIN_C , DMD_PIN_D , DMD_PIN_E };

// pin OE must be one of PB0 PB1 PA6 PA7
#define DMD_PIN_nOE PB0
#define DMD_PIN_SCLK PB7 //LAT

// All this pins also must be selected from same port!
uint8_t custom_rgbpins[] = {PA6, PA0,PA1,PA2,PA3,PA4,PA5 }; // CLK, R0, G0, B0, R1, G1, B1

#endif

// Fire up the DMD object as dmd<MATRIX_TYPE, COLOR_DEPTH>
// We use 64x32 matrix with 8 scans and 4bit color:

DMD_RGB <RGB64x32_S8_Eu057,COLOR_4BITS> dmd(mux_list, DMD_PIN_nOE, DMD_PIN_SCLK, custom_rgbpins, DISPLAYS_ACROSS, DISPLAYS_DOWN, ENABLE_DUAL_BUFFER);

#define BRIGHTNESS_DEFAULT 50  // (brightness 0-255, recomended 30-100)

void setup(void)
{
  Serial1.begin(1000000);

  dmd.init(); 
  dmd.setRotation(-45-90);
  dmd.clearScreen(true);

}

void loop(void)
{
  if (Serial1.available() >= 4) {
  // Read the bytes
    firstByte = Serial1.read();
    secondByte = Serial1.read();
    thirdByte = Serial1.peek();
    thirdByte1 = Serial1.read();
    // Check the second byte in the buffer
    fourthByte = Serial1.peek();
    fourthByte1 = Serial1.read();
    data_len = thirdByte | (fourthByte << 8 );
    BUFFER_SIZE = data_len/2; 

   if (firstByte == 0xC0 && secondByte == 0XCE){

     Serial.println("packet found");
     Serial.print("DATA_LENGTH(HEX): ");
     Serial.println(data_len,HEX);
      Serial.print("DATA_LENGTH(DEC): ");
      Serial.println(data_len,DEC);
     Serial.print("ARRAY ELEMENTS(HEX): ");
      Serial.println(BUFFER_SIZE,HEX);
      Serial.print("ARRAY ELEMENTS(DEC): ");
      Serial.println(BUFFER_SIZE,DEC);

      while (data_len > 0) {

        if(Serial1.available() > 0 ){

         rlen = Serial1.readBytes((uint8_t*)Image_buffer, data_len);
         Serial.println("Received data:");

              for (int i = 0; i < BUFFER_SIZE; i++) {

             Serial.println(Image_buffer[i],HEX);
             }
          i++;
         }
        Serial.println(i);
        data_len = 0;
      }
    } 
    dmd.setBrightness(20);
   dmd.clearScreen(true); 
   dmd.drawRGBBitmap(dmd.width() - 96, 0, Image_buffer, 96, 64);            
  }
}
board707 commented 2 months ago

i send a matrix value which data length 0x3000 = 6144 pixels = (packet 122800 bytes) from PC every 1 second via FTDI that use USART1 in STM32F411CEU6, baud rate =1000000, and when i sent the packet the serial was stuck after receive 1 or 2 packet,

Hi Sending 122800 bytes with 1000000 baudrate requires a (122800 * 8 ) / 1000000 = 0.98 sec. Doing it once a second you load the microcontroller to 98% to read the Serail only, leaving virtually no time for anything else. However, working with matrices requires significant resources, involving both the main code and interrupts.

Addition: stop.. 6144 pixels need 12288 bytes only, not 122800.

ZOUALFIKAR commented 2 months ago

Thanx for your prompt reply and sorry it's a mistake when i wrote, yes its 12288 because every pixel is 2 byte that absolutely 12288.

that's mean 12288 bytes with 1000000 baudrate requires a (12288 * 8 ) / 1000000 = 0.098 sec. but the serial stuck when i add the commands that relate to the DMD_RGB.h :

do you have any idea to solve this issue please, if i need to change some thing in your code library or any another idea to try it for solving the issue, by the way this an example for the matrix that i sent every 500 m.s

array = [ 0x0000,0x0000, ..... (many lines slkipped) ]

board707 commented 2 months ago

that's mean 12288 bytes with 1000000 baudrate requires a (12288 * 8 ) / 1000000 = 0.098 sec

Yes, but that doesn't change much. Do not forget that in order for the image on the matrix to not flicker, its refresh rate must be at least 30 times per second. Since your panels has a scan factor 8 and 4 bits of color, this means that we must run the image update procedure at least 30 8 4 = 960 times per second. So that is, approximately every millisecond. And your data transfer takes 98 ms. Since the controller has only one core, these two processes will undoubtedly interfere with each other - and, most likely, the operation of the DMD_STM32 library will disrupt transmission over the serial, since the DMD runs in an interrupt and stops other processes. I don’t currently have a ready-made solution to get around this. In any case, this requires a very serious rewrite of both the library and the Serial class so that they can work out their tasks one at a time. This can probably be circumvented by moving the project to a Rasberry Pi Pico 2040 controller (supported by the DMD_STM32 library), which has two cores. Then you could run the DMD_STM32 library on one core and the serial transfer on another. However, such a redesign requires a lot of work and experience in designing multi-core applications

ZOUALFIKAR commented 2 months ago

do you think if i use FreeRTOS or Thread will be solve this issue? And on the other side if i want to make a simple library like yours (but just suitable for STM32F411) do you have an advice how can i start because i am newer in this field (build library) but i have an ambition to do it , maybe we can cooperate to establish a solution with this library.

board707 commented 2 months ago

do you think if i use FreeRTOS or Thread will be solve this issue?

Some users reported that the library is incompatible with RTOS, see the issues. The work with the HUB75 panels requires a very tight intervals, and it needs updates much more frequently than the typical RTOS switching frequency.

maybe we can cooperate to establish a solution with this library.

it could be interesting. How do you imagine this? What is your experience with STM32 controllers?

ZOUALFIKAR commented 2 months ago

until now unfortunately, i don't have an obvious imagine but maybe at the first i need some documentation to understand where can improve the code or not, it's not a big experience in stm32 but at all i have an experience in coding arduino.

ZOUALFIKAR commented 2 months ago

Hi my friend do you have a documentation for your library? that will help me to rebuild it to suitable with serial port, because i still stuck without any solutions with stm32, except the solution that you gave it in your comment

In any case, this requires a very serious rewrite of both the library and the Serial class so that they can work out their tasks one at a time.

board707 commented 2 months ago

Documentation is my problem. Some sections of the code contain comments that clarify the logic of the work. But many functions are not documented in any way. Right now I'm trying to write a short reference on the library methods. Unfortunately, my English is not good and google doesn't always translate correctly, so this is a difficult process for me.

ZOUALFIKAR commented 2 months ago

Unfortunately to hear that, but i think you can do it to complite your work as a proficional, by the way i have another question do you use DMA ( Direct memory access ) in your library and if the answer no, do you think that we can use DMA to save data without load CPU and in this way maybe solve that problem (two process in the same time, refresh scan rate and serial read from USART)

board707 commented 2 months ago

do you use DMA

This question cannot be answered unambiguously :) The library works with several types of matrices and contains code for three different families of controllers. The solution is different in each case. DMA is used wherever possible and where it using provides an advantage in panel update time, see the table: DMD type STM32F1 STM32F4 RP2040
Monochrome HUB-12 SPI DMA DMA DMA
Monochrome HUB-12 Parallel - - DMA
RGB HUB-75 - DMA DMA

As you can see, in your case (STM32F411 and RGB panel) - the data transfer work using DMA.

Unfortunately, DMA only reduces the load on the core, but is not a solution to the problem. As I wrote above, the protocol for the hub75 panel requires updating data hundreds of times per second. Data transfer can be done via DMA, but the initialization of this transfer is carried out through an interrupt anyway - and therefore conflicts with other processes

ZOUALFIKAR commented 2 months ago

So sad, any way can you tell me where exactly i can modify the code in your library to will be suitable with serial read via USART because as i see i don't have another solution to achieve it with STM32 and thanx a lot for your helpful

board707 commented 2 months ago

By the way, your code to read data from Serial not seems too optimal for me:

while (data_len > 0) {

        if(Serial1.available() > 0 ){

         rlen = Serial1.readBytes((uint8_t*)Image_buffer, data_len);
         Serial.println("Received data:");

              for (int i = 0; i < BUFFER_SIZE; i++) {

             Serial.println(Image_buffer[i],HEX);
             }
          i++;
         }
        Serial.println(i);
        data_len = 0;
      }
    } 

Perhaps the number of failures can be reduced by rewriting the data reception.

Look at the code - every time, when there is no next byte in the serial buffer, you consider that the transfer is completed and the array is full. You don't even check the size of the received data before sending it to the matrix! Meanwhile, UART is an asynchronous protocol and small interruptions in transmission are common. It would be more correct to wait a little and read the data further until the entire array has been read. I would also throw out the readBytes function and read it as normal Serial1.read().

In addition, since we already have problems with time, spending time on printing the contents of the entire array is very wasteful.

I would run something like this:

uint8_t* byte_ptr = (uint8_t*)Image_buffer;   // pointer to buffer as uint8_t*
uint32_t timeout = 5;       // read timeout 5 ms
uint32_t time_mark = millis();

while (data_len > 0) {        // while image is not complete
    if (Serial1.available() > 0 ){
            *byte_ptr = Serial1.read();
              byte_ptr++;
              data_len--;
              time_mark = millis();
         }
    else if (millis() - time_mark > timeout) {  // stop if nothing is received in 5ms
        break;
      }
    } 
 if (data_len == 0) {    // draw the bitmap only if image received completely
    dmd.clearScreen(true); 
    dmd.drawRGBBitmap(dmd.width() - 96, 0, Image_buffer, 96, 64);  
}
board707 commented 2 months ago

Hmmm What's this? dmd.setRotation(-45-90);

The setRotation() is a method of Adafruit GFX library, see the manual for acceptable parameters: https://learn.adafruit.com/adafruit-gfx-graphics-library/rotating-the-display

board707 commented 2 months ago

Hi @ZOUALFIKAR Today I tested the simultaneous operation of Serial and the DMD library. Everything works fine without any modifications to the library. Test conditions: Board - BlackPill STM32F411 Screen - 3 x 64x32 RGB panels Serial1 baudrate - 921600 Packet size - 2048...8192 bytes To control data integrity each data packet was equipped with CRC16 checksum.

I changed your receiving code as I wrote in comment above.
I think the results suggest that the library is not interfering with Serial's work. The problem is somewhere on your side.

ZOUALFIKAR commented 1 month ago

Hi @board707 Thank u my friend for your advices and response , u are right the problem was in baud rate not in the library, i tested my code with difference baud rate to 500000 it was working without any problem, the problem was in baud rate 100000 and above that.

Again thanks and it was pleasure that i made a conversation with u, great wishes i hop to u.

board707 commented 1 month ago

Thanks for your feedback. Even though you have solved the issue, I recommend that you rework your code. It has obvious problems that I pointed out above. By rewriting your code, I was able to transfer data at a speed of 921kbit, so the problem probably is not in the transfer speed, but in your code. With best wishes to your project :) Dmitry