supercrab / arduino-seven-segment

Arduino Library for 7 Segment LCD/LED Displays
20 stars 7 forks source link

Driver M5450 needs 36 clock cycles. #5

Closed tistructor closed 2 years ago

tistructor commented 2 years ago

I was using a card with "8.8.8.8.::" with your library and I encountered a problem with the example of basic.ino. The initial 5 flashes did not occur, it seemed that the screen.clear () function did not work.

I took a look at the functions of the library, in particular the display () and I realized that with the M5450 driver only 35 clocks are sent including the initial bit, instead it is necessary to send 36 clocks according to the data sheet. I also put 35 bits of data for the M5450 driver and the example now works properly.

https://user-images.githubusercontent.com/24445373/176171851-9be1eb44-f310-4b6a-9443-553636829a14.mp4

 * Table of supported drivers stored in program memory
 */
PROGMEM const driver driverTable[] = {
    { "M5450", 34+1, false, true, true, false, false }, // 34 data bits and 1 load clock
    { "M5451", 35, false, true, true, false, false },
    { "MM5452", 32, false, true, true, false, true },
    { "MM5453", 33, false, true, true, false, false },
    { "AY0438", 32, true, false, false, true, false },
    { "BT-M512RD-DR1", 35, false, true, true, false, true }
};

Basic.ino modified. The modification to the display () is also reported because my shield is not connected as you suggested but there are 7-segment displays in different order.

/*
   http://code.google.com/p/arduino-seven-segment/

   This is a basic demo of the seven segment library
   that works will work with a single 7 segment display component

   It will turn on all display segments then turn them off 5 times,
   count to 9, then display all the characters available.

   You will need to set your driver and your screen configuration in the line
   screen.begin("AY0438","8");

*/
#include <SevenSegment.h>

/******************************
 * LIBRERIA MODIFICATA PER LA MIA SCHEDA LX1204
 * 
 * (175)
 * PROGMEM const driver driverTable[] = {
    { "M5450", 34+1, false, true, true, false, false }, // 34 data bits and 1 load clock
    { "M5451", 35, false, true, true, false, false },
    { "MM5452", 32, false, true, true, false, true },
    { "MM5453", 33, false, true, true, false, false },
    { "AY0438", 32, true, false, false, true, false },
    { "BT-M512RD-DR1", 35, false, true, true, false, true }
  };
 * 
 * in SevenSegnebt.cpp in (651)display function:
 * 

void SevenSegment::display(){
 boolean tempData[64];
 uint8_t segmentCount = _device.segments;

  // If driver is cascaded then doubles the total segment count
  if (_cascaded){
    segmentCount *= 2;
  }

  // Set data enable to low
  if (_device.dataEnable){
    digitalWrite(_pinLoad, LOW);
  }

  // Send initial bit if required
  if (_device.initialBit){
    digitalWrite(_pinData, HIGH);
    pulseClock();
  }

// convert data for LX1204 Board
  for(uint8_t i = 0; i < 8; i++){
    tempData[i+16] = _data[i];
    tempData[i+24] = _data[i+8];
    tempData[i] = _data[i+16];
    tempData[i+8] = _data[i+24];      
  }
  for(uint8_t i = 32; i < 64; i++){
    tempData[i] = _data[i];
  }

  // Write data segments
  if (_device.segmentsOrderInc){

    // Output data in ascending order
    for (uint8_t i = 0; i < segmentCount; i++){
      digitalWrite(_pinData, tempData[i] ? HIGH : LOW);
      pulseClock();
    }
  }
  else{

    // Output data in descending order
    for (int8_t i = segmentCount - 1; i >= 0; i--){
      digitalWrite(_pinData, tempData[i] ? HIGH : LOW);
      pulseClock();
    }
  }

  // Pulse load if required
  if (_device.pulseLoad){
    pulseLoad();
  }

  // Set data enable to high
  if (_device.dataEnable){
    digitalWrite(_pinLoad, HIGH);
  }
}
 * 
 * 
 ******************************/

#define CLOCK 7 // Arudino digital 44 -> AY0438 clock
#define DATA 6   // Arudino digital 46 -> AY0438 data

SevenSegment screen(CLOCK, DATA);

uint16_t counter = 0;

void setup() {
  Serial.begin(9600);
  // Set display driver AY0438 and screen definition
  screen.begin("M5450", "8.8.8.8.:");

}

void loop() {

  // Turn on all segments and turn off 5 times
  for (int i = 0; i < 5; i ++) {

    // Turn all known segments on
    screen.on();
    delay(100);

    // Turn all known segments off
    screen.clear();
    delay(100);
  }

  // Count to 9
  screen.setAlignment(RIGHT);
  for (int i = -999; i < 10000; i++) {
    screen.printNumber(i);
    delay(10);
  }

  // Display all characters one by one
//  screen.setAlignment(LEFT);
//  char c[4];
//  for (int i = 32; i <= 127; i++) {    
//    c[0] = i;
//    screen.print(c);
//    delay(200);
//  }
}
tistructor commented 2 years ago

M5450_LX1204_PinoutSeg

supercrab commented 2 years ago

Thanks for raising this issue.

I don't have a M5450 to test but I will update my library to send an extra clock pulse.

Your segments are hooked up in the reverse order,. To fix you can change the following line:

PROGMEM const driver driverTable[] = {
    { "M5450", 35, false, false, true, false, false }, // this line has changed
    { "M5451", 35, false, true, true, false, false },
    { "MM5452", 32, false, true, true, false, true },
    { "MM5453", 33, false, true, true, false, false },
    { "AY0438", 32, true, false, false, true, false },
    { "BT-M512RD-DR1", 35, false, true, true, false, true }
};
tistructor commented 2 years ago

Hi, I tried to change parameter 4 with both false and true but the result on the display does not change, I read the minutes instead of the hours and vice versa. The order of the display is : My Display --- Library 4 --- 2 3 --- 1 2 --- 4 1 --- 3

Look at the photo (15:02)

IMG_20220630_150219

tistructor commented 2 years ago

I tried to put true (row 682) inside the display () function and the numbers come out as in the photo, if I put false the order of the segments is wrong, and nothing is read.

I found a bug :

// Copy driver data into the struct in main memory
            _device.name = (char*) pgm_read_word(&(pDriverTable[i].name));
            _device.segments = (uint8_t) pgm_read_word(&(pDriverTable[i].segments));
            _device.pulseLoad = (boolean) pgm_read_word(&(pDriverTable[i].pulseLoad));
            _device.segmentsOrderInc = (boolean) pgm_read_word(&(pDriverTable[i].segmentsOrderInc));
            _device.initialBit = (boolean) pgm_read_word(&(pDriverTable[i].initialBit));
            _device.cascadable = (boolean) pgm_read_word(&(pDriverTable[i].cascadable));

where the variables are boolean or uint8_t pgm_read_byte and non pgm_read_word are needed.

// Copy driver data into the struct in main memory
            _device.name = (char*) pgm_read_word(&(pDriverTable[i].name));
            _device.segments = (uint8_t) pgm_read_byte(&(pDriverTable[i].segments));
            _device.pulseLoad = (boolean) pgm_read_byte(&(pDriverTable[i].pulseLoad));
            _device.segmentsOrderInc = (boolean) pgm_read_byte(&(pDriverTable[i].segmentsOrderInc));
            _device.initialBit = (boolean) pgm_read_byte(&(pDriverTable[i].initialBit));
            _device.cascadable = (boolean) pgm_read_byte(&(pDriverTable[i].cascadable));
tistructor commented 2 years ago

for now I have to complete my method again. Perhaps a variable in "struct driver" is needed which indicates the correct sequence of displays. For example, for my "3412" tab compared to the default value of "1234" and add some code.

supercrab commented 2 years ago

My bad, try this to define the order of the digits! :) Let me know if it works.

display.setWiring(RIGHT_TO_LEFT)

tistructor commented 2 years ago

does not work. Only the two central LEDs are correct but the 4 displays have incorrect characters.

tistructor commented 2 years ago

It's an old card and I think for routing convenience they set the links in this mode. M5450_LX1204

supercrab commented 2 years ago

I just noticed your screen definition is wrong. This might work...

screen.begin("M5450", "8.8|8.8.");

supercrab commented 2 years ago

The screen definition tells the software the segments are attached to the driver IC and has to match the wiring. Your screen has 2 outputs for the colon character and I don't think my library can support this wiring :(

tistructor commented 2 years ago

screen.begin("M5450", "8.8.8.8.|"); It works this way but I always have to use the part of code that I put on the display ().

Thanks

tistructor commented 2 years ago

This is a small quick test to check how it works like a watch:

/*

*/
#include <SevenSegment.h>
#include <RTClib.h>

RTC_Millis rtc;

const int pinClock  =  7;// clock
const int pinData   =  6;// data

const int pinP1     =  8;// P1
const int pinP2     =  9;// P2

SevenSegment screen(pinClock, pinData);

void setup() {
  Serial.begin(9600);

  //Set display driver M5450 LX1204
  screen.begin("M5450", "8.8.8.8.|");
  screen.setAlignment(RIGHT);
//  screen.setWiring(RIGHT_TO_LEFT);
  //Turn all known segments off
  screen.clear();
  delay(1000);
  screen.on();
  delay(100);
  screen.clear();
  rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
}

uint16_t   ore;
uint16_t   minuti;
uint16_t   secondi;

uint16_t ora7Seg;
uint16_t ora7SegPrec;
uint16_t secondiPrec;

void loop() {

  DateTime now = rtc.now();

  //  Serial.print(now.hour(), DEC);
  //  Serial.print(':');
  //  Serial.print(now.minute(), DEC);
  //  Serial.print(':');
  //  Serial.print(now.second(), DEC);
  //  Serial.println();

  ore = now.hour();
  minuti = now.minute();
  secondi = now.second();

  ora7Seg = ore * 100 + minuti;
  if (ora7Seg != ora7SegPrec) {
    screen.printNumber(ora7Seg);
    ora7SegPrec = ora7Seg;
  }

  if (secondi != secondiPrec) {
    screen.setSegment(32, !screen.getSegment(32));
    screen.setSegment(33, !screen.getSegment(33));
    screen.display();
    secondiPrec = secondi;
  }

}
supercrab commented 2 years ago

Looks like you got it working! 👏🏽👏🏽👏🏽😊