Go Down

Topic: Looking to hire for (hopefully) simple LCD display output (Read 910 times) previous topic - next topic

hhaase

Right now I just don't have time to start digging into code again,  so I'm looking to hire somebody to work on a design for me, both code and schematic.    I'll take over at that point to handle PCB layout and such.  Normally I work with KiCad for schematics but this one is simple enough I don't mind hand drawn or PDF schematics.  I can provide a basic schematic of some of it to get things started.

Basic concept is to read the outputs from an old microcontroller driven numeric display.  I need to read a pair of BCD (Binary coded decimal) outputs,  and 16 logic outputs.  These are all TTL 5v logic outputs.  When each of those logic lines goes low, it will output the digits from the pair of BCD's into an I2C OLED display.  The system constantly cycles through those 16 logic outputs, at a rate under 1mhz.   

There are two different display variations that I'd need to work with, both with the same input signals, but different layouts to where it outputs the digits.  I'd like this to be software selectable via a momentary button, since there are additional variations I'd like to program in the future. 

Prefer to base around the 28pin DIP 328P if possible.  I know it's a pain and probably means extra circuits due to the I/O limits.  Know Verilog?  A PAL/GAL could probably handle it.

If this works out well I do have many other potential designs going forward along similar lines.





patduino

Probably not many Verilog programmers here, but you might find a few that can help.  Why an FPGA?
There are 10 types of people in the world, those who understand binary, and those that don't.

hhaase

Just thinking of ways to simplify any external circuitry needed to keep the Arudino down to the smaller I/O sizes.  A pair of 8-to-3 encoders would probably work just fine too.

I'm pretty flexible in that regard, just as long as it's based around the ATMega 328 series chips.  I'm more concerned with not jumping up to an ATMega 2560 or similar,  as I'm not set up for handling larger QFP's just yet.   


-Hans


PaulMurrayCbr

Does it really need to run at the full 1MHz if it's just operating a display? Does it really need to update the display only when one of these 16 outputs goes low? Why not just poll the BCD outputs every few milliseconds, and update the OLED when necessary?

If you run the BCD outputs into a parallel-in/serial-out shift register (you only need one if its two BCD digits), a Teensy could easily do the job. You'd need 5 IO pins: two for i2c, and clock, data, and latch for the shift register.
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

hhaase

I'm looking to read the digital outputs from part of a pre-existing board design,  so I'm stuck having to read both BCD's and all 16 of the strobe lines.  But you're right, it can be polled at any time, it doesn't need to be in sync.   

1mhz is the processor speed of the board I'm reading the output from, and that's only a small part of the overall function that it does,  there's a LOT of other I/O's in that board which are outside the scope of this project.  I just need to read the numeric outputs to replace a large/old high voltage set of displays without going to all discreet logic and transistors to drive a pile of 7-segment LED's. Too spendy and time consuming to produce in that manner.

I can e-mail to provide a lot more specifics,  I'm just wary of posting too much here as I've had competitors steal my concepts in the past.


PaulMurrayCbr

#5
Aug 31, 2017, 10:21 am Last Edit: Aug 31, 2017, 10:26 am by PaulMurrayCbr
Ok.


I don't have an OLED myself to test this with, but if you are just replacing the display then this is simply a matter of reading the BCD outputs and dumping it somewhere. The nature of BCD makes this even easier.

You could use bit-fiddling on a PORT, but it's really not necessary.

Code: [Select]

void loop() {
  int newValue =
    (digitalRead(3)==HIGH ? 10 : 0) +
    (digitalRead(4)==HIGH ? 20 : 0) +
    (digitalRead(5)==HIGH ? 40 : 0) +
    (digitalRead(6)==HIGH ? 80 : 0) +
    (digitalRead(7)==HIGH ? 1 : 0) +
    (digitalRead(8)==HIGH ? 2 : 0) +
    (digitalRead(9)==HIGH ? 4 : 0) +
    (digitalRead(10)==HIGH ? 8 : 0);

  if(newValue != currentValue) {
    currentValue = newValue;
    writeValueToOLED(currentValue);
  }

  delay(50); // 20 frames per sec - more than enough
}
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

jarnoldbrown

I take it this is a multiplexed display, so you need to latch the digit data when the strobe for each individual digit is asserted. But still not clear, are there 32 digits of display? A simple diagram would help here.
Also, it would be interesting to know the speed of the strobes. It may be that the digit data could be sampled by a fairly slow micro, or it may require hardware(including FPGA/GAL/PAL) latching. Once again, some sort of timing diagram would help.
Sounds like an interesting project.

hhaase

Aw hell,  none of my competitors are going to be here, I'll just open up what I'm trying to do. 

I need to display the score outputs for a couple generations of pin-ball machines, for doing bench repair and diagnostics on the main CPU/Driver boardsets.    For now I need to handle two different versions.   One version has 6-digit scoring for each of the 4 players,  the other version has 7 digit scoring.   Plus an additional 4 digits for credit/ball counters.    You need to be able to read these displays to handle the various diagnostic menus built into the main boardset.   

These boards are running Motorola 6800 series processors, which are 1mhz bus speed,  but there's plenty of other calculations going on besides the score displays. Each cycle through the code it increments (or is it decrements?) the strobe number.  Some games have more code than others, depending on the rules set,  so speed won't be consistent from game to game.  It's been a long time since I've had a logic probe on them so I don't know the actual speed.  And yes, they are latching.

Like you said, Paul, it's basically just reading the BCD's and dumping them to a location, and the location is determined by which strobe is low.  If strobe 6 is low, BCDA goes to the "1's" digit on player 1,  and BCDB goes to the "1's" digit for player 3. 

Here's a pretty good layout showing the '6-digit' version.   
http://www.pinwiki.com/wiki/images/b/b8/08-masterdisplayboard-sys3-6.pdf

The '7-digit' version has the same number/type of signals,  just arranges them differently to get another digit per player.  I can provide scans of old manuals to give the digit layouts.

I had previously sold a version of this using discreet logic and transistors, to drive 7-segment LED's.   But I lost all my design work, and ran out of PCB's.   That and it was a compromise design to keep cost down. Not sure if forum rules would allow direct linking to my business site.  If you do a google search on "DB-05-011", the part number, it'll come up.  Going software/OLED, instead of discreet circuits, will let me expand to other manufacturers/generations of machines in later versions.   So I'm expecting this to be the first design, with future code revisions for sure to handle different manufacturers.   Eventually I'll probably need to do a whole new design based around the 2560 in order to handle alphanumeric displays too.


PaulMurrayCbr

#8
Sep 01, 2017, 10:48 am Last Edit: Sep 01, 2017, 10:53 am by PaulMurrayCbr
Quote
Like you said, Paul, it's basically just reading the BCD's and dumping them to a location, and the location is determined by which strobe is low.  If strobe 6 is low, BCDA goes to the "1's" digit on player 1,  and BCDB goes to the "1's" digit for player 3. 
Hmm.

Is there at least a tiny pause where all the strobes are high? As in, they are all normally high, and occasionally one of them goes low?

There might be a way to sense when any of them go low. Perhaps an OR gate (or a cascade of them to get as many inputs as you need) with an inverter on the inputs. Run that into an arduino interrupt and sense the RISING condition (because they are inverted). Or run all the strobes into an AND gate and sense the FALLING condition. Same thing.

The interrupt should do nothing but sense which strobe is low and grab the current BCD bits and stuff them somewhere. It has to be fast. It doesn't have time to think. The main loop() has the job of driving the display.

So, let's say that the BCD inputs are all on PORTB (pins 14-19), and the strobes are on PORTD (pins 2-6 and 11-13) on pins 3-6 and 11-12. Which pins are on what ports depends on which particular arduino you have, of course. Pin 2 is the interrupt, and we avoid pint 13 because there's an LED on it.

The declaration s would be:
Code: [Select]

const byte STROBEMASK = 0b10000001; // mask out pins 2 and 13
volatile boolean scoreNotify = false;
// PORTD - low means that the strobe has gone low
volatile byte strobe;
volatile byte bcd[8]; // each byte is a copy of PORTB at the time the strobe went low



the interrupt logic would be something like:
Code: [Select]

void ISR() {
    byte thisStrobe = PORTD | STROBEMASK;
    strobe &= thisStrobe;
    // to be fast, the compiler must convert this switch/case to a computed jump.
    // If it doesn't do that, assembler may be required.
    switch(thisStrobe) {
      case 0b11111101: bcd[1] = PORTB; break; // pin 3
      case 0b11111011: bcd[2] = PORTB; break; // pin 4
      case 0b11110111: bcd[3] = PORTB; break; // pin 5
      case 0b11101111: bcd[4] = PORTB; break; // pin 6
      case 0b11011111: bcd[5] = PORTB; break; // pin 11
      case 0b10111111: bcd[6] = PORTB; break; // pin 12
      // no default. If the strobe is not one of these six values, then something odd is going on
    }
    scoreNotify = true;
}


and the loop logic wold be:
Code: [Select]

void loop() {
  byte _strobe;
  byte _bcd[8];

  // this is the block to deal with contention

  noInterrupts();
  if(!scoreNotify) {
    interrupts();
    return;
  }

  _strobe = strobe;
  memcpy(_bcd, bcd, 8);
  strobe= ~0;
  scoreNotify = false;
  interrupts();

  // at this point, we have now retrieved the most recent updates to the digits

  for(int i = 1; i<= 6; i++) {
    if(_strobe & (1<<i) == 0) {
      // grab the BCD value from _bcd[i] and put it at position [i] on the display.
    }
  }

}



I suppose the "scorenotify" gear is irrelevant, because the display will *always* be doing some sort of update if it's running at 1mhz. The cde could just assume that it's always set.

This setup does leave you a little short on ins, but You could probably use the analog pins as outputs for your i2c display.

 
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

hhaase

Normally there is always one strobe low,  except maybe an extremely brief moment caused by switching time in the logic chips feeding everything.   This particular design doesn't have a 'blanking' signal per-se. 

I'm starting to wonder if there may be another Atmel chip that could be a better fit.  Something like an ATMega-16L maybe?  They do have a 40pin PDIP I could easily use until I'm able to handle a QFP-44.

-Hans




PaulMurrayCbr

Normally there is always one strobe low,  except maybe an extremely brief moment caused by switching time in the logic chips feeding everything.
Well, that's a hassle.

Rather than using an interrupt, then, write a routine that reads the data (blocking while it does so) and call that routine every 100ms or so.

That routine would have to wait for strobe input 1 to go HIGH, then wait for strobe input 1 to go LOW, then copy out the BCD bits. Same again for the other six inputs. It would be an ugly-looking chink of code, but meh. You may need to resort to asembler to make it fast enough. Write out the bitmasks longhand.


Code: [Select]


byte bcd[6];

void readBcd() {
  while((PORTD & 0b00000010) == 0)
    ; do nothing - wait for the strobe to go HIGH

  while((PORTD & 0b00000010) != 0)
    ; do nothing - wait for the strobe to go LOW
  bcd[0] = PORTB;

  while((PORTD & 0b00000100) != 0)
    ; do nothing - wait for the strobe to go LOW
  bcd[1] = PORTB;

  while((PORTD & 0b00001000) != 0)
    ; do nothing - wait for the strobe to go LOW
  bcd[2] = PORTB;

  // etc
}


Hopefully, the logic will be fast enough to catch the edge of the wave and ride it. The initial wait for the first strobe to go HIGH is there to handle the possibility that this routine might get called juuust as the strobe is about to go from that first digit to the next.

The while should get compiled down to a logical and and then a 'jump if zero" and a "jump if not zero" instruction. The assignment uses a constant for the array index, so the compiler should just turn this into a "plonk the value here in memory".

The ordering of the pins matters, of course. To make it a touch more bulletproof, you could add that "wait for new next strobe to go HIGH" loop for each pin. Ideally, of course, in all cases that loop will exit immediately - but it may glitch and have to wait for the next go-around.


Yet another alternative is to capture the strobe port (PORTD), the data port (PORTB), and then the strobe port again. If the strobe port is the same before and after reading the data port, then examine it to work out which set of BCD bits you have just captured. The issue, however, is that it may alias - you may call the read routine at a rate that means it never gets called during the moment when digit 3 is being transmitted.
 




http://paulmurraycbr.github.io/ArduinoTheOOWay.html

hhaase

The question I have is, if there's no blanking signal or interrupt signal, does it necessarily HAVE to follow along with the sequence?  Can it be more along the line of a brute force loop that just reads everything at once and acts upon what signal is actually low at that given time. It's been a LONG time since I've written code with any competency,  but I can still formulate some logic in my head.  I know it's not elegant, but it should still fit into 32kb,   and I'm not against using external memory if needed.   


Poll strobes and BCD.
        If strobes = 0b1111111111111111 or 0b000000000000000 then run "no signal" subroutine.
        If strobes = 0b0111111111111111 then write BCDA to master digit 1 and BCDB not used this strobe
        ...
        If strobes = 0b1000000000000000 then write BCDA to player 1 digit 1 and BCDB to player 4 digit 1


The 'no signal' routine will blank the display, increment a counter, and after counter hits a certain number will display 'no signal' on the OLED.



But I just keep rolling back to the lack of I/O's here, and trying to think of an easy way to deal with this problem while not locking me down too much, and keeping things versatile for future code revisions.     All the above discussion has been dealing with Williams style displays.   If I want to add those used by Bally, Atari, Gottlieb, and others,  then things get a lot more complicated as they use very different architectures.

Would it potentially make things easier to actually use a pair of processors?   One could simply to process the strobes down from 16 bit parallel to a serial signal,   the 2nd processor would handle the BCD's and actual display computations.

-Hans


 




hhaase

Ok, looks like I found somebody to collaborate with on this project, so going to be handling it directly with him.

Thank you all for the collaboration, I do appreciate it.

Go Up