My Digital Tachometer - putting it all together

Go To Last Post
192 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To review, I am making a digital tachometer that looks like this:

To drive the 7 segment LEDs, I am using a MAX7219, and for the bar graph around the perimeter, I'm using 5 PCA9922s, which are shift registers similar to 74HC595s but higher power (and different pinouts). There are also three LEDs to backlight the "RPM" nomenclature and are driven by spare outputs of one of the PCA9922s. After experimenting with the AS4 simulator and trying different ideas writing code, I have frozen the hardware design of my tachometer.

|=============================================================================| | | | ATtiny 26 Microcontroller | | | | +----v----+ | | MOSI/PB0 -| 1 20 |- PA0/ADC0 Analog Dimmer Input | | MAX7219 Data Out MISO/PB1 -| 2 19 |- PA1/ADC1 | | Serial Clock SCK/PB2 -| 3 18 |- PA2/ADC2 | | Crank Sensor Input PCINT0/PB3 -| 4 17 |- PA3/AREF Capacitor to ground | | VCC -| 5 16 |- GND | | GND -| 6 15 |- AVCC | | 16 mHz crystal XTAL1/PB4 -| 7 14 |- PA4/ADC3 MAX7219 Select/Latch | | 16 mHz crystal XTAL2/PB5 -| 8 13 |- PA5/ADC4 PCA9922 Select/Latch | | T0/PB6 -| 9 12 |- PA6/ADC5 | | Reset RESET/PB7 -| 10 11 |- PA7/ADC6 PCA9922 data out | | +---------+ | | | ===============================================================================

Through my experimenting I found the USI is the most efficient way to send data to the MAX7219. But the bar graph is another story. Breaking the serial stream into 8 bit (single byte) chunks is quite cumbersome. I need to send 40 bits in series. Since it is a bar graph, there is a series of continuous ones followed by a series of zeros. I'll use a loop to count through the ones then the zeros. This takes more clock cycles that I expected in the loop, but is is way better than breaking the 40 bits into 5 bytes. I'll use the USI clock for the PCA9922 even though the data is output from a different pin than the USI data. The USI clock toggles with one clock cycle while an I/O pin takes two. As discussed in previous threads, on the bar graph, I plan to use software PWM to vary the intensity of the top lit segment to do a kind of 'interpolation' between segments. It is a kind of anti-aliasing for the top segment (if that makes sense). I am using an external analog signal to define the LED intensity for overall dimming at night (just like the way the dimming in a car works). This will be easy with the MAX7219. But since the bar graph top segment uses PWM, I need to make sure the whole program runs fast enough to provide enough granularity so I can do both overall intensity AND top segment PWM. The crank sensor input uses the Pin Change Interrupt to count edges from 40 'holes' (80 edges) in a disk (flywheel). I count these edges for .075 secs. This gives one tenth the RPM (ie. at 2500 RPM = 250 counts). If I want more resolution, I found that I can average, say, ten readings, but NOT divide by ten. In this thread, I will be sharing the step-by-step assembly of the whole project. I have a small machine shop (including CNC) and will be custom building the enclosure, LED diffuser, engraved face, etc. So I'll show all that along with the code development and testing. I have already completed the diffuser and engraved face, so in my next few posts, I'll show the process of fabricating them. Plus, I should have PCBs in a few weeks, so stay tuned.... This forum has been such a great help to my being able to even do this, I think it will be a way for all that helped to see the fruit of their efforts (since this has DEFINITELY been a team effort). It is also a way for me to thank Kartman, clawson, bobgardner, joeymorin, et al.... I don't know if this is the proper forum, so forgive me if it isn't. :wink: Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

Last Edited: Thu. Feb 19, 2015 - 07:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pins and needles!

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I don't know if this is the proper forum,

You could host it on Atmel Spaces and use your own blog their to document build steps as you go. It ties code, design documents, bug tracker, forum even together in one place for all time. The only proviso Atmel stipulate is that, like SourceForge (on which it is based) it must be an open source project and you effectively give Atmel rights to the design.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sounds pretty cool!

Why all the extra chips? Looks like you could use just an AVR and charlieplex the LEDS.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I count these edges for .075 secs. This gives one tenth the RPM (ie. at 2500 RPM = 250 counts). If I want more resolution, I found that I can average, say, ten readings, but NOT divide by ten.


What works well in many of these situations is to keep a small circular buffer of the last n readings. For example, you could have 10 entries over 0.75 seconds and the total would be your RPM.

You can then make the balance between number of entries and responsiveness.

In any case, with even just a few entries it tends to smooth out readings that are small numbers, and as with other "oversampling" can increase precision. If you have a few bytes of SRAM for the buffer and current index, the processing is minimal (especially if the buffer size is a power of 2, and/or adds up to a magic number as with your sampling rate and a 10-place buffer).

Quote:

Breaking the serial stream into 8 bit (single byte) chunks is quite cumbersome.

Quote:

but is is way better than breaking the 40 bits into 5 bytes.

You've lost me on this one. I'll assume that when all 40 are lit, you are at the redline and that represents a certain RPM. For the sake of discussion, let's say that RPMmax is 4000 and each fully-lit LED represents 100rpm.

So you calculate that you are at 2550 rpm. Divide that by 100 and you get 25 with a remainder of 50. So 25 get fully lit, and you fuss with the remainder.

"value" is now 25
LOOPon:
  Is "value" >= 8?  
  If so, 
    -- output a 11111111 byte
    -- subtract 8  from value
    -- goto LOOPon

  If not,
    -- output the partial byte 1/0 combination
    -- calculate how many off bytes
    -- use that to jump into the 5-place table below (Duff's device? ;) 

LOOPoff5:
  Output 00000000 byte
LOOPoff4:
  Output 00000000 byte
LOOPoff3:
  Output 00000000 byte
LOOPoff2:
  Output 00000000 byte
LOOPoff1:
  Output 00000000 byte
  

I don't know where you fuss with the remainder. The first 0 bit in the combination byte?

Just one way to approach it. I'd tend to call it "tricky" rather than "cumbersome", but it is fun to do such programming challenges IME.

The painful /100 can be made much less painful with a judicious choice of RPMmax so that "value" is just a mask or shift/mask.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
You could host it on Atmel Spaces
...[snip] ...
you effectively give Atmel rights to the design.
Thanks. :wink: I'm not ready to do that right now.
Torby wrote:
Why all the extra chips? Looks like you could use just an AVR and charlieplex the LEDS.
Yes, that would work. At this point though, I don't see a significant advantage in saving three 50 cent chips. So starting over with hardware redesign (along with PCB layout) isn't in the cards at this time. I'll keep it in mind in the future. :wink:
theusch wrote:
What works well in many of these situations is to keep a small circular buffer of the last n readings.
Yes, exactly my plan. I just didn't know how to put in words as well as you did. :wink:
theusch wrote:
I'd tend to call it "tricky" rather than "cumbersome", but it is fun to do such programming challenges IME.
I did essentially what you suggest and ran it through the simulator. It took three times as many clock cycles as the loop I wrote. So this is why I used the word cumbersome.
    1. I set the data line high 2. toggle the clock on/off 25 times
    3. pull data line low
    4. toggle clock on/off for the remaining bits
DONE! It seems way too simple to ignore. :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

Last Edited: Thu. Sep 5, 2013 - 11:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IME you might have trouble getting balanced brightness with the different-coloured LEDs if all driven with the same current.

That said, it may not matter. Looking at your design, if the orange and/or yellow are a bit brighter than the green it may not matter. If the yellow and red on the ends are brighter--so much the better.

Looking at the picture, my "RPMmax" is 7000? (I only see 36 LEDs in the picture, with an extra yellow at the low end and otherwise 5 per (I assume) 1000rpm? So it is really 200rpm for one LED and an extra at the bottom?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
IME you might have trouble getting balanced brightness with the different-coloured LEDs if all driven with the same current.
I have LEDs that are similar brightness. But you are right, it may not matter.
theusch wrote:
Looking at the picture, my "RPMmax" is 7000?
You were right the first time, 4000 max rpm. I don't see a need to have LEDs for 100-400 RPM. The bottom segment is for 500 RPM. The engine won't be running below that.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

You were right the first time, 4000 max rpm.

So it then ends up to be one LED for each 100rpm over a threshold.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
So it then ends up to be one LED for each 100rpm over a threshold.
Yep! You got it. :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made solid models of the gauge to get a sense of how everything goes together (the back cover is aluminum but I show it as transparent to allow for viewing what's inside):

One of the challenges of this gauge is diffusing the LEDs. Through hole LEDs are molded with a lens/diffuser, but it seems the SMT LEDs rarely are. I ran into this problem with a project for a customer and solved it after some experimentation. It now works quite well.

Each segment (LED) needs to be optically isolated so the light doesn't 'bleed' from one to another. So each segment needs to be a separate piece of acrylic with something opaque between them. With a bar graph, you want minimal space between the segments. Since the bar graph is an arc, each segment is a trapezoidal shape.

To make the diffuser, I knew it would be easiest to use my CNC mill.

I began with 1/2" translucent white acrylic sheet that is used for back lit signs. I found that an eighth inch thickness will diffuse the LED to minimize the 'hot' spot and not absorb too much light. The idea is that the CNC would cut a series of trapezoids in an arc and opaque epoxy would be cast around them. Since the desire is to have minimal space between segments, the cutter would need to be really skinny - unless something different could be devised. I cut every other trapezoid so there was a larger space between them, and made two pieces like this:

Then sandwiched them together like this.

The four holes in the corners are pinned to keep everything aligned. Epoxy is poured into the larger hole on the left and allowed to cure. The pins are removed and most of the plastic is machined away to leave this:

It is important to have a light barrier between segments and with only .014" (.36mm) between segments, it is doubtful the epoxy will be sufficient. I didn't want to use black epoxy because I wanted to REFLECT the light rather than absorb it. So I got an aluminized mylar granola bar wrapper and cut strips that I could insert between the trapezoids before sandwiching and epoxying. You can see the darker lines from these strips in the photo above.

The 7 segment displays will poke through the rectangular hole and the RPM nomenclature is illuminated by the smaller rectangular section below it. It will then be covered by the engraved face below:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very cool.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Holy [phneep]!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been working on the code and getting a little discouraged. :? It looks like being able to control the bar graph intensity with my current approach won't work. :(

Running at 16mHz, with a refresh rate of 80 Hz, a 3 bit PWM for the top lit bar graph segment, and 3 bit PWM for bar graph dimming, the program loop has 3,125 clock cycles to do its job. So far it uses about 2,300 cycles. Since I still have to incorporate the PWM functions, it looks like I could easily bust the budget. :shock: (Plus, it would be nice to have the option to go to 4 or more bit PWM).

So I am looking at a different strategy. To control the bar graph dimming, I am looking into using the ATtiny26's hardware PWM connected to the chip enable pins of the PCA9922s (shift registers). This changes the rules enough that there is plenty of margin and there is no longer any concern about having enough time. Plus, increasing PWM from 3 to 4 bits (or more) is no problem. However, doing this requires re-arranging the furniture somewhat. :wink:

I am assuming that the PWM will use the resources of timer1 so I will need to use timer0 for the RPM timing. Timer0 does not have a compare feature so I'll have to deal with that.

Question:
Is it possible to preload a non-zero value in the timer register and count overflow interrupts?

Also, the PWM output pin is currently used for the Pin Change interrupt from the crank sensor. Because of the limitations of the tiny26's PCINT, it is problematic to use it on a different pin. BUT, I discovered the external interrupt INT0 has a mode to detect any change as well as either edge. :wink: So I'll connect the crank sensor to INT0 instead. Here are the pinouts with these changes:

|=============================================================================|
|                                                                             |
|                          ATtiny 26 Microcontroller                          |
|                                                                             |
|                                 +----v----+                                 |
|                       MOSI/PB0 -| 1    20 |- PA0/ADC0  Analog Dimmer Input  |
|   MAX7219 Data Out    MISO/PB1 -| 2    19 |- PA1/ADC1                       |
|       Serial Clock     SCK/PB2 -| 3    18 |- PA2/ADC2                       |
|   BarGraph Dim Out  PCINT0/PB3 -| 4    17 |- PA3/AREF  Capacitor to ground  |
|                            VCC -| 5    16 |- GND                            |
|                            GND -| 6    15 |- AVCC                           |
|     16 mHz crystal   XTAL1/PB4 -| 7    14 |- PA4/ADC3  MAX7219 Select/Latch |
|     16 mHz crystal   XTAL2/PB5 -| 8    13 |- PA5/ADC4  PCA9922 Select/Latch |
| Crank Sensor Input    INT0/PB6 -| 9    12 |- PA6/ADC5                       |
|              Reset   RESET/PB7 -| 10   11 |- PA7/ADC6  PCA9922 data out     |
|                                 +---------+                                 |
|                                                                             |
===============================================================================

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not to derail your thread, but that's not a "Waiex" in your avatar? Oh, no. The canopy and nose are completely different.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Torby wrote:
that's not a "Waiex" in your avatar?
No, it's my own design... I call it aeroHAWK. :wink:

It is single place and powered by a converted Corvair engine. Currently it is inside my computer - I'm trying to figure out how to get it out! :shock:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where does one obtain a Corvair engine?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Where does one obtain a Corvair engine?
Just monitor Craig's list, they pop up from time to time. The 'best' engines for aircraft are generally the ones that the Corvair collectors do not want.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Currently it is inside my computer - I'm trying to figure out how to get it out!

Open the hangar doors and just fly it out?

Place the computer on a good piece of Styrofoam, put that stack in some water and hope it believes it is an aircraft carrier? (The CD tray could be ejected to resemble one of those aircraft lifts they have..)

Put pontoons on your aeroHAWK and let Jeckson fly it out?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Open the hangar doors and just fly it out?
:lol: LOL! :lol: Thanks for the laugh!

I can talk about airplanes 24/7, but that is another forum. :wink: For this forum however, I still have a question.

I want to switch from timer1 to timer0 for the RPM timer. The challenge is that I'm using the output compare feature of timer1, but timer0 doesn't have that feature.

The F_CPU is 16mHz, and the prescaler is 1/1024. Timer1 compares the counter to 194 to get a period of .0125 Sec. My thinking is to pre-load the register (TCNT0) with 61 after each overflow (in the ISR) so there are 194 counts left before it overflows.

Is this feasible?

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The F_CPU is 16mHz, and the prescaler is 1/1024. Timer1 compares the counter to 194 to get a period of .0125 Sec. My thinking is to pre-load the register (TCNT0) with 61 after each overflow (in the ISR) so there are 194 counts left before it overflows.

Is this feasible?

Yes, but if there's too much delay between timer0 overflowing, and your code reloading the timer, the timer0 period will be long. You have around 1024 instruction cycles to play with, that should be plenty, unless you're doing a lot of work with interrupts disabled.

Hmmm... What setup are you planning for timer1? You might be able to use timer1 for both PWM dimming and RPM counting - use OCR1B for the PWM dimming, OCR1C for setting the period, and the TOV1 interrupt for the RPM count.

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mnehpets wrote:
You have around 1024 instruction cycles to play with, that should be plenty
Okay, great, that was my thinking also.
mnehpets wrote:
You might be able to use timer1 for both PWM dimming and RPM counting
After reading more about the PWM, I looked into that. I want the PWM frequency to be several hundred hertz, so it seems a lot easier if I can separate the PWM and RPM timing.

THANKS! :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
I want the PWM frequency to be several hundred hertz, so it seems a lot easier if I can separate the PWM and RPM timing.

It's not too difficult to run both functions on the same timer. Hmmmm.. Is the 80Hz used for RPM measurement? What you could do is to set timer1 to run at 400Hz, and use OCR1B for PWM. For the RPM timing, you simply need to do the RPM measurement every 5 timer overflows.

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mnehpets wrote:
It's not too difficult to run both functions on the same timer.
Thanks, I see what you're saying. :wink:

Is there a compelling reason to use only one timer?

There are two timers in the micro, it appears to also be quite easy to use both timers. So which way is better?

It looks like six of one - half dozen of the other. :wink: So now I have to pick....

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, debugging is apt to be a bit easier if you use separate Timer/Counters for separate functions.

But that only applies to those of us who have to occasionally debug some code...

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Code errors? You guys don't make THOSE, do you?

Why count revolutions, 'stead of timing them and dividing?

In the 70s, I wanted to make a CMOS optical tach for model airplanes. I couldn't figure out how to divide. Well, duh, I knew how to program 2708 eproms, just program one so you could look up the RPM based on the time. These days? Just divide.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Torby wrote:
Why count revolutions, 'stead of timing them and dividing?
Why NOT?

There is more than one way to do it. Is there a compelling reason to do one or the other? Six of one - half dozen of the other.... :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
mnehpets wrote:
It's not too difficult to run both functions on the same timer.

Is there a compelling reason to use only one timer?

There are two timers in the micro, it appears to also be quite easy to use both timers. So which way is better?

It looks like six of one - half dozen of the other. :wink: So now I have to pick....

No, there's no compelling reason for either choice. If you use two separate timers, it's easier to have the two functions completely independent. On the other hand, with the two timer approach, you get a timing constraint on the reloading of the timer value.

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

This is a very cool, ambitious project, your machining skills are awesome!

Where do all of the shift registers and other digit driving ICs go in the 3D models you have shown?

It seems like you are trying to achieve PWM of the bar graph by using a successive shift register loading technique. Wherein you load the shift registers for 1,2,3 or 4 "time slots" within a certain 4-slot PWM period to achieve four levels of overall brightness. Is that sort of correct?

Do you have brightness control over the whole bar-graph, plus an additional "level" of brightness control for the top segment? Or, is it only the top segment that has the 4-level brightness control?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
So I am looking at a different strategy. To control the bar graph dimming, I am looking into using the ATtiny26's hardware PWM connected to the chip enable pins of the PCA9922s (shift registers). This changes the rules enough that there is plenty of margin and there is no longer any concern about having enough time. Plus, increasing PWM from 3 to 4 bits (or more) is no problem. However, doing this requires re-arranging the furniture somewhat. :wink:
Just remember that if you're mixing two PWM signals to drive one display element, you must be mindful of 'beating'. Specifically (as discussed in some of your other threads), the display will beat with a frequency equal to:
    modulo
This is fine, so long as the beat frequency is faster than POV, say 60 Hz.

If the beat frequency is zero, you must still take care that the two PWM are in phase.

The advantage of doing both PWM on the AVR is you have control over both.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Just remember that if you're mixing two PWM signals to drive one display element, you must be mindful of 'beating'. Specifically (as discussed in some of your other threads), the display will beat with a frequency equal to:
    modulo
This is fine, so long as the beat frequency is faster than POV, say 60 Hz.
Thanks for keeping me on top of this JJ. When this was discussed in my other thread, I googled 'beating' and 'aliasing' and I found the same formula, as well as this:
    beat freq. = abs (freq1 - freq2)
:wink: Yes, I am aware, and yes I am taking it into account. :wink: :wink: I plan to use a fairly high frequency... say between 1kHz and 4kHz.

Using different timers as discussed above makes it easier to make adjustment to this if needed. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
Where do all of the shift registers and other digit driving ICs go in the 3D models you have shown?
It isn't very clear in the images, but there are two PCBs stacked. The shift registers are on the back side of the front board (close to the LEDs they drive). The 20 pin SOIC package that is easily seen, is the MAX7219 that drives the seven segment displays.
Chuck-Rowst wrote:
It seems like you are trying to achieve PWM of the bar graph by using a successive shift register loading technique. Wherein you load the shift registers for 1,2,3 or 4 "time slots" within a certain 4-slot PWM period to achieve four levels of overall brightness. Is that sort of correct?
Yes, exactly. I plan to use eight levels of brightness.
Chuck-Rowst wrote:
Do you have brightness control over the whole bar-graph, plus an additional "level" of brightness control for the top segment?
Yes. The shift registers have a 'chip eneble' pin that I will drive with a PWM. This is the subject of the last few posts (i.e. which timer to use for what).

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

The PCA9922's have a configurable current drive (15 - 60 mA). What current drive value are you using?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
The PCA9922's have a configurable current drive (15 - 60 mA). What current drive value are you using?
I will do some experimenting, but expect to be between 15 mA and 20 mA.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

It seems from your descriptions of the Bar Graph section of your instrument that you are connecting 5 PCA9922's serially into one long 40 bit shift register. Correct?

If so, I think you should consider NOT taking this approach. Instead, drive the 9922's as five parallel 8-bit shift registers - that is with 5 separate data lines, one common clock and one common load line. I believe this approach will offer you a number of advantages. However, before I launch into an elaborate discussion of these benefits, please tell me if you have enough I/O lines on your processor to accomodate this "5 wide" approach.

Also, do you have any FPGA experience?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
you are connecting 5 PCA9922's serially into one long 40 bit shift register. Correct?
Correct
Chuck-Rowst wrote:
tell me if you have enough I/O lines on your processor to accomodate this "5 wide" approach.
Barely. I have 4 lines left, but I'd have to use the data-in of the USI. This should be okay, since I don't use the USI for any input. This is what I have currently.
|=============================================================================|
|                                                                             |
|                          ATtiny 26 Microcontroller                          |
|                                                                             |
|                                 +----v----+                                 |
|                       MOSI/PB0 -| 1    20 |- PA0/ADC0  Analog Dimmer Input  |
|   MAX7219 Data Out    MISO/PB1 -| 2    19 |- PA1/ADC1                       |
|       Serial Clock     SCK/PB2 -| 3    18 |- PA2/ADC2                       |
|   BarGraph Dim Out  PCINT0/PB3 -| 4    17 |- PA3/AREF  Capacitor to ground  |
|                            VCC -| 5    16 |- GND                            |
|                            GND -| 6    15 |- AVCC                           |
|     16 mHz crystal   XTAL1/PB4 -| 7    14 |- PA4/ADC3  MAX7219 Select/Latch |
|     16 mHz crystal   XTAL2/PB5 -| 8    13 |- PA5/ADC4  PCA9922 Select/Latch |
| Crank Sensor Input    INT0/PB6 -| 9    12 |- PA6/ADC5                       |
|              Reset   RESET/PB7 -| 10   11 |- PA7/ADC6  PCA9922 data out     |
|                                 +---------+                                 |
|                                                                             |
===============================================================================

Chuck-Rowst wrote:
Also, do you have any FPGA experience?
None (I had to google it to know what it was).

In case you missed earlier threads... I am a mechanical engineer / toolmaker / moldmaker. My knowledge in electronics is only adequate (self taught), but I do seem to pick things up very quickly. :wink:

FYI - I have the PCB layout finished. I don't know what you have in mind, but anything more than changing a few traces will need to provide significant advantages to warrant a redesign.... :wink:

Can you put the advantages into a concise sentence?

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We EE's are not known for our conciseness!!!

Here's what I'm thinking:
The bar graph (as you pointed out) has only a few basic display modes (40 I think) which are basically a bunch of 1's (lit LEDs) followed by 40-a bunch of 0s. The uppermost lit LED will do something special.

My idea is to only load four of the 9922's once, but load the fifth 9922 (the one with that topmost modulated last LED) repetitively to achieve the desired dimming of the topmost LED. You only reload the other four 9922's as you need to update the overall "value" of the Bar Graph. The advantage is you can write to the one active 9522 at a nominal 5 times rate that you would do with the 40 bit shift register approach.

Also, with the 5-wide shift register approach you can "broadside" load the 40 bits in approximately one-fifth the time it would take you to serially load the 40bit long register. There's a special software technique for doing this, but it relies on having the N-wide shift register to begin with.

Yes, I realize your main background is as a machinist/mechanical designer. But you are apparently a Lifelong Learner with few excuses. I thought you may have had some FPGA exposure along the way. I was going to suggest a possible FPGA alternative to the 9922's. But no big deal. We all have different approaches to our projects, these approaches are always inherently rooted in our acquired skill and knowledge sets. In other words, you use what you have and you run with it! I think you've figured this out already on your own.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
My idea is to only load four of the 9922's once, but load the fifth 9922 (the one with that topmost modulated last LED) repetitively to achieve the desired dimming of the topmost LED.
First, let me say thank you for your interest in my project!

I like your idea, and I have some concerns.

When I was working on a purely software solution to the overall dimming (in conjunction with the top lit segment), I tried many things in the simulator to speed things up. One thing I found was that it was cumbersome to separate the 40 bits into 5 bytes. Overall, it was faster to just spit out 40 bits in a loop, even though the loop adds 4 clock cycles each pass to monitor the count.

Your suggestion would also require converting 40 bits to 5 bytes.

By going to the ATtiny26's hardware PWM for the overall dimming, speed is no longer a factor. Unless I am missing something, I understand that your suggestion is an attempt to make things faster.

However, is also sounds like you are familiar with some coding trick that may make the 40 bit to 5 byte conversion more efficient, which piques my interest (as a Lifelong Learner :wink: ).

Chuck-Rowst wrote:
you use what you have and you run with it!
Yeah... to a hammer, everything looks like a nail. :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, my scheme would still use the ATTiny's PWM to control overall brightness via the Output Enable inputs of the 9922's.

In your scheme how would you get that "special" dimming for the topmost lit LED you described? I got the idea you would have to reload the complete 40 bits of the shift register continuously with the same pattern except for the topmost LED bit which would be 0 or 1 in a sequence that would give you the desired brightness of that topmost LED.

In my scheme I would not "calculate" the bit pattern(S) to be shifted into the 9922's. Instead, I would create a "hard-wired" table containing all possible patterns that could be shifted to the 9922's. You figure out the contents of this table during the design process and it is stored as part of the program in the ATTiny's Flash. When you load the 9922's, you simply read successive table entries and transfer them to the GPIO data lines and "click" the common 9922 clock line for each transfer.

The table is created in C-language a similar way that you make a normal N x M array. E.g. "unsigned char Table[n][m];" Except ypou include the keyword "const" in the declaration and assign the desired "hard" values to the array in the same statement. This is how we make a "look-up table" ("LUT") in C. Here's an example:

( "TableX" is the name I've chosen for this example, you would pick your own name like you do with any variable declaration.)

const unsigned char TableX[3][4]=
{
{0,1,2,3},
{10,11,12,13},
{20,21,22,23}
};

I've used decimal values in the example, but for bit patterns like you would need for your application you would probably use hex or binary bit-field values for ease of composition and debugging. Your table would probably be considerably longer - probably 40 rows at least.

To speed things up a litle faster you would choose 5 GPIO bits in the same output port for the data lines. That way you simply read a value from the table and write it directly to that GPIO port as a single byte value.

By the way this is a standard programming trick in many languages. To pick up a speed advantage where you have some type of limited or repetitive calculation or bit manipulation, you devise some sort of clever look-up table which holds all possible "answers" and merely "pop" them out of the table according to the same parameters you would have used to calculate them in the CPU. I've used this technique in countless programs, for various reasons - speed advantage being the main one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
I got the idea you would have to reload the complete 40 bits of the shift register continuously with the same pattern except for the topmost LED bit which would be 0 or 1 in a sequence that would give you the desired brightness of that topmost LED.
Yes, this is what I planned.
Chuck-Rowst wrote:
In my scheme I would not "calculate" the bit pattern(S) to be shifted into the 9922's. Instead, I would create a "hard-wired" table containing all possible patterns that could be shifted to the 9922's.
AHA! I love it! :wink: :shock:

Some time ago (my memory is vague), I had a project where I considered solving a problem in a similar way (without a micro) using a 27C256 EPROM.

Chuck-Rowst wrote:
You figure out the contents of this table during the design process and it is stored as part of the program in the ATTiny's Flash.
In this case (as I attempted to point out above), I don't need the extra speed. On the other hand, many of the choices made in this design were made because it would teach me something new. So I am interested in learning this. :) I think this will be useful for many things.
Chuck-Rowst wrote:
To speed things up a little faster you would choose 5 GPIO bits in the same output port for the data lines. That way you simply read a value from the table and write it directly to that GPIO port as a single byte value.
This might be a little tricky since the ATtiny26 has limitations as to what pins are used for some functions. But as I see it, this is only a minor inconvenience.
Chuck-Rowst wrote:
By the way this is a standard programming trick
Yes, now that you tell me about it, I am familiar with it. But because of my inexperience with C (and probably other reasons), it never dawned on me. Besides, I wouldn't have known how to implement it without your brief tutorial above. :wink: I will be studying it to make sure I get it all. :wink:

Cris

P.S. Sorry for taking so long to respond, I had to attend to things that took me away from my computer.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay... I have changed to the following pinout to incorporate the look up table method that Chuck proposed:

//==============================================================================
//                                                                             |
//                          ATtiny 26 Microcontroller                          |
//                                                                             |
//                                 +----v----+                                 |
//        MAX7219 Load   MOSI/PB0 -| 1    20 |- PA0/ADC0  Analog Dimmer Input  |
//    MAX7219 Data Out   MISO/PB1 -| 2    19 |- PA1/ADC1  PCA9922 Load         |
//        Serial Clock    SCK/PB2 -| 3    18 |- PA2/ADC2  PCA9922 Data Out A   |
//    BarGraph Dim Out   OC1B/PB3 -| 4    17 |- PA3/AREF  Capacitor to ground  |
//                            VCC -| 5    16 |- GND                            |
//                            GND -| 6    15 |- AVCC                           |
//      16 mHz crystal  XTAL1/PB4 -| 7    14 |- PA4/ADC3  PCA9922 Data Out B   |
//      16 mHz crystal  XTAL2/PB5 -| 8    13 |- PA5/ADC4  PCA9922 Data Out C   |
//  Crank Sensor Input   INT0/PB6 -| 9    12 |- PA6/ADC5  PCA9922 Data Out D   |
//               Reset  RESET/PB7 -| 10   11 |- PA7/ADC6  PCA9922 Data Out E   |
//                                 +---------+                                 |
//                                                                             |
//==============================================================================

The PCB layout is also updated. I put together the look up table, too. It took some head scratching since I had not done anything like this before, so I had to restart the thought process a few times. :?

Plus, since I'm using ImageCraft, the syntax of Chuck's example needed a little tweak but here is my table:

__flash unsigned char TablePORTA[37][8]=
{
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80},

  {0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80},
  {0x04, 0x04, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80},
  {0x04, 0x04, 0x04, 0x00, 0x00, 0x80, 0x80, 0x80},
  {0x04, 0x04, 0x04, 0x04, 0x00, 0x80, 0x80, 0x80},
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x80, 0x80, 0x80},
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x84, 0x80, 0x80},
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x80},
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x84},

  {0x14, 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x84},
  {0x14, 0x14, 0x04, 0x04, 0x04, 0x84, 0x84, 0x84},
  {0x14, 0x14, 0x14, 0x04, 0x04, 0x84, 0x84, 0x84},
  {0x14, 0x14, 0x14, 0x14, 0x04, 0x84, 0x84, 0x84},
  {0x14, 0x14, 0x14, 0x14, 0x14, 0x84, 0x84, 0x84},
  {0x14, 0x14, 0x14, 0x14, 0x14, 0x94, 0x84, 0x84},
  {0x14, 0x14, 0x14, 0x14, 0x14, 0x94, 0x94, 0x84},
  {0x14, 0x14, 0x14, 0x14, 0x14, 0x94, 0x94, 0x94},

  {0x34, 0x14, 0x14, 0x14, 0x14, 0x94, 0x94, 0x94},
  {0x34, 0x34, 0x14, 0x14, 0x14, 0x94, 0x94, 0x94},
  {0x34, 0x34, 0x34, 0x14, 0x14, 0x94, 0x94, 0x94},
  {0x34, 0x34, 0x34, 0x34, 0x14, 0x94, 0x94, 0x94},
  {0x34, 0x34, 0x34, 0x34, 0x34, 0x94, 0x94, 0x94},
  {0x34, 0x34, 0x34, 0x34, 0x34, 0xb4, 0x94, 0x94},
  {0x34, 0x34, 0x34, 0x34, 0x34, 0xb4, 0xb4, 0x94},
  {0x34, 0x34, 0x34, 0x34, 0x34, 0xb4, 0xb4, 0xb4},

  {0x74, 0x34, 0x34, 0x34, 0x34, 0xb4, 0xb4, 0xb4},
  {0x74, 0x74, 0x34, 0x34, 0x34, 0xb4, 0xb4, 0xb4},
  {0x74, 0x74, 0x74, 0x34, 0x34, 0xb4, 0xb4, 0xb4},
  {0x74, 0x74, 0x74, 0x74, 0x34, 0xb4, 0xb4, 0xb4},
  {0x74, 0x74, 0x74, 0x74, 0x74, 0xb4, 0xb4, 0xb4},
  {0x74, 0x74, 0x74, 0x74, 0x74, 0xf4, 0xb4, 0xb4},
  {0x74, 0x74, 0x74, 0x74, 0x74, 0xf4, 0xf4, 0xb4},
  {0x74, 0x74, 0x74, 0x74, 0x74, 0xf4, 0xf4, 0xf4},

  {0xf4, 0x74, 0x74, 0x74, 0x74, 0xf4, 0xf4, 0xf4},
  {0xf4, 0xf4, 0x74, 0x74, 0x74, 0xf4, 0xf4, 0xf4},
  {0xf4, 0xf4, 0xf4, 0x74, 0x74, 0xf4, 0xf4, 0xf4},
  {0xf4, 0xf4, 0xf4, 0xf4, 0x74, 0xf4, 0xf4, 0xf4},
}; 

The PCA9922 shift registers are used to drive the 36 bar code segments plus three LEDs used to illuminate the "RPM" nomenclature. So the top three outputs of the last shift register are always on (and one output isn't used).

Chuck-Rowst wrote:
My idea is to only load four of the 9922's once, but load the fifth 9922 (the one with that topmost modulated last LED) repetitively to achieve the desired dimming of the topmost LED. You only reload the other four 9922's as you need to update the overall "value" of the Bar Graph.
With the "5 wide" approach, isn't it just as fast to load all 5 since it is done in parallel?

Plus, wouldn't it be faster because you don't have to figure out which four to avoid or if they should be avoided?

EDIT: Oh, I also just realized:

Chuck-Rowst wrote:
drive the 9922's as five parallel 8-bit shift registers - that is with 5 separate data lines, one common clock and one common load line.
With the common load line, I couldn't do one at a time if I wanted.... :shock:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
With the common load line, I couldn't do one at a time if I wanted....

Do you care the rest just get the same data over and over again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
Do you care the rest just get the same data over and over again.
Since the program will need to be able to load all shift registers at once anyway (because there will be times the data won't be the same), it turns out to be easier. :wink: So no, don't care....

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

You are correct, with the parallel load topology there is no advantage to loading just one 9922. My original fuzzy thinking involved some sort of individual 9922 enabling function - this is NOT needed, nor is it beneficial.

Next issue: Do you envision some sort of "interference" between the overall PWM dimming applied to the Output Enables of the 9922's? Don't you have to synchronize the loading of the top-most 9922 with the PWM so that the special top-most PWMing occurs while the 9522 are actually driving the LEDs? If you load the top-most 9522 while the chain is in it "dark time" (i.e. PWM is off) you will never see the augmentive dimming action on the topmost LED, or you will see it in some "choppy" manner. I think this would have been the case with your original 40-bit serial version as well. Have you thought about this?

The solution would be to somehow co-ordinate the 9522 loading with the PWM dimming signal. You would probably do that using one of the interrupts associated with the ATTiny counter that generates the dimming PWM.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lets say you want to do 4 brightnesses, so need to redraw the led tower 280Hz, every 3.5ms, and the top bit is a 1 for 0,1,2, or 3 passes depending on brightness.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
Do you envision some sort of "interference" between the overall PWM dimming applied to the Output Enables of the 9922's? Don't you have to synchronize the loading of the top-most 9922 with the PWM so that the special top-most PWMing occurs while the 9522 are actually driving the LEDs?
Although I have never used PCA9922s, I am assuming Output Enable is independent of the input (as it is in every other chip I have used). The data sheet doesn't call it a Chip Enable, so the only interference I expect is due to aliasing of the two PWM frequencies. Also there is a special sequence of toggling /OE, LE, and CLK to enter an 'error detection' mode that will need to be avoided.

If my assumption is wrong and the output enable has an effect on the input, I'll switch to a different chip. On Semiconductor has the CAT4008 with the same pinout and no 'error detection' mode, and the data sheet is clearer that the /OE doesn't effect input.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Lets say you want to do 4 brightnesses, so need to redraw the led tower 280Hz, every 3.5ms, and the top bit is a 1 for 0,1,2, or 3 passes depending on brightness.
Yes, just what I plan. With the only difference being, I will have 8 brightnesses with a refresh freq of 640 Hz. :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

The "interference" I refer to is what you are calling "aliasing", not any logical loading/clocking mechanism within the 9922s. (I have never used these either.)

What is the frequency/period and duty cycle range of the overall PWM brightness signal you will be applying to the 9922 Output Enables?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
What is the frequency/period and duty cycle range of the overall PWM brightness signal you will be applying to the 9922 Output Enables?
1kHz PWM, 30% - 100% duty cycle.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

When your 1KHz PWM is running at less than 100% duty cycle you will have a "beat frequency" effect between it ( the PWM dimming control) and the rate (640Hz) at which you update the topmost segment of the bar graph. I can't say exactly what visual effect you will see when this happens. The nominal beat freqency is 360Hz which is well beyond the flicker frequency detection of human vision. Still, I have had visible effects caused by various secondary effects in similar types of stroboscopic situations as what you are doing here with the bar graph PWMing. E.g. beating of harmonics of the fundamental switching frequencies.

When you get the bar graph working, you should slowly adjust the PWM through its entire range of 30% to 99% (100% is not an issue because it represents a steady-on case). If you see any ill effects, there are a few software remedies which will likely correct the sitauation. Flicker effects are typically most visible in low-light situations.

By the way, in my experience PWMing a LED at 30% does not have much of a visual dimming effect. I'm not sure what you expected lighting conditions are with this instrument. However, in "dark room" conditions (e.g. an office with the ceiling lights turned off, but light coming from other instruments, desk lamps, etc.), I have found that PWMs above around 10% have a tendency to "blind" your vision because of their perceived brightness. So, you may find in your situation that you really need to run the PWM down into that 10% range for a "comfortable" display. I'd imagine that would occur during night flying in your case, but again I don't know your expected operational situations.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
1kHz PWM, 30% - 100% duty cycle.
Chuck-Rowst wrote:
I have had visible effects caused by various secondary effects in similar types of stroboscopic situations
Chuck-Rowst wrote:
you may find in your situation that you really need to run the PWM down into that 10% range for a "comfortable" display
Thanks Chuck! Since I have not done this before, I plan to experiment to find the best solution. I merely guessed at what I thought would be a starting place. Thank you for your additional input, it is very helpful. :wink:

If I run into flicker problems, my plan has been to increase the PWM frequency (say... to maybe 4kHz). But if there are still issues... as you say, I will likely need to synchronize the two PWMs.

I will receive the PCBs on Monday. So right now, I'm stuck at calculating the current-set resistors for the PCA9922s. I've scoured the datasheet and cannot find ANYTHING! :shock: It's not a very good data sheet. :?

I have been working on the mechanical parts. I have finished the lens/window and am starting to CNC the bezel (I've got the programming done).

Next week I should have more pictures as the parts come together. :D

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
I will receive the PCBs on Monday. So right now, I'm stuck at calculating the current-set resistors for the PCA9922s. I've scoured the datasheet and cannot find ANYTHING! :shock: It's not a very good data sheet. :?
Quote:
Current controlled outputs (LED[7:0])
////////////////////////////////////////////////////////////////////////////////
Symbol Parameter                  Conditions                  Min  Typ  Max Unit
Iol    LOW-level output current   VO = 0.7 V; Rext = 910 Ω   17.5 19.5 21.7 mA
                                  VO = 0.7 V; Rext = 470 Ω   35.4 38.1 40.8 mA

Voltage across Rext is likely to be constant, so Rext * Iol should be constant:
910 * 0.0195 = 17.745
470 * 0.0381 = 17.907

Seems to be close, within 2% of 18. So we can derive a formula:

Rext * Iol = 18
      Rext = 18/Iol

So if you wanted a 60 mA output:

Rext = 18/0.060
           = 300 ohms

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
So if you wanted a 60 mA output:
Rext = 18/0.060
     = 300 ohms

THANKS JJ! That is the only thing I could think of doing to get a value, but I knew it involved making assumptions I wasn't sure about. :?

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Above, I wrote:
I will receive the PCBs on Monday.
I use ExpressPCB for my circuit boards. It takes them three business days to make 4 layer boards then UPS second day is another two. So I expected the boards on Monday, but they came yesterday instead! :D UPS used only one day to get them to me.

ExpressPCB has an inexpensive service that requires the boards to be 2.5 x 3.8 inches. I then cut them to the appropriate size and shape on my CNC.

This photo shows the boards as made by ExpressPCB and the boards after I cut them out. The two at the top are as received (front and back), and the bottom three are what I cut. You can see the bar graph laid out on the one on the left and the 7 segment display board on the right. The small board is for IR sensors for the opto-interrupter (if I decide to go that way).

I have also been working on the enclosure. In this photo you see the bezel, engraved face, LED diffuser, and tinted lens/window, along with the PC boards.

The next order of business is to populate the 7 segment display board and get the displays working... :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks fantastic!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Looks fantastic!
THANKS JJ! :wink: I'm quite happy with how everything is coming together.

I populated the 7 segment display board. Here is what it looks like - front and back:

And of course you can't hide from Murphy.... :? I have some minor interference between the crystal and the place where the ISP header goes (lower right). :cry: I'll need to extent the header to be a little taller. Hopefully it will not interfere with the housing.

I also started populating the bar graph PCB. I found that the yellow LEDs that I have claim to be amber, but they are somewhere between orange and red. :? I'll need to get some that are really yellow.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
And of course you can't hide from Murphy.... :? I have some minor interference between the crystal and the place where the ISP header goes (lower right). :cry: I'll need to extent the header to be a little taller. Hopefully it will not interfere with the housing.
Would simply shaving a bit off the header's plastic separator solve the problem?... or is it that the connector on the end of the programming cable interferes, too?

Perhaps if you used a female header like this one, then use a male-male 'gender bender' made out of a long-pin male header like this one, with the separator pushed in to the centre of the pins.

I've used a similar setup to program an Arduino Pro Mini with a 6x1 female header like this one contact-soldered (i.e not using the pins in the through-holes). A 6x1 long-pin male header was used to connect it to an FTDI breakout for programming.

In my case, the advantage was that I got reliable programming without having exposed pins on the Pro Mini when in use.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Perhaps if you used a female header like this one, then use a male-male 'gender bender' made out of a long-pin male header
Thanks JJ, that might be a good idea. :wink: I can see some advantages, and I think I already have the parts.

I put the pieces together for a preliminary test fitting. Here is what it looks like, front and back:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi aeroHAWK,

Everything looks great! Very professional.

I use Express PCB too, its a great proto PCB service. Simple to use, great quality.

You might be able to just "lift" the crystal up a bit and bend it away from the header to get enough clearance. Or actually mount it at 90-degrees from your intended position, bending the leads into the holes. ( Be careful not to short its metal case to any of the exposed traces or pads - maybe a piece of mylar tape. )

If your airplane has any degree of vibration (like most I am familiar with), you will want to reinforce those "oil tank" capacitors and the crystal with some RTV "potting". These capacitors have a lot of "sprung mass" - i.e. their weight is relatively high in comparison to their soldered lead area. These leads, or their solder joints, will eventually fracture from longterm vibration stress in an aircraft environment. It is common practice these days to "goop" non-SMD components on PCBs that are to be used in "rugged service" applications. Aircraft use is a typcial example of"rugged service". Of course you wouldn't do this until the unit is completely debugged, tested and ready for final, long term installation in the aircraft.

The typical gooping technique is to load the RTV into a hypodermic syringe (without the needle) and squeeze it carefully where needed on the board to achieve the desired degree of sturdiness without completely obliterating the remaining components. Hobby stores carry various types of disposable non-medical syringes which are designed for this type of precise glue and sealing work.

Let the programming commence!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I really love how this thread has gone through earlier stages to something being a complete implementation.

And I am quite impressed by what you do with your CNC some metal and epoxy! In the latest photos of TRT (The Real Thing) it looks like it was just pulled out of a commercial packaging. I can imagine how nice your cocpit will look with a series of home-made instruments, all as meticulously crafted as the one above!

Congratulations, and I really hope it will fly! Open those hangar doors!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The photo-op on top of the PCB CAD drawings is a nice touch ;)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
Everything looks great! Very professional.
JohanEkdahl wrote:
it looks like it was just pulled out of a commercial packaging.
Thanks Chuck and Johan. It's always great to get nice feedback. :wink:
joeymorin wrote:
The photo-op on top of the PCB CAD drawings is a nice touch ;)
Thanks JJ, it seems you notice some of the subtle things... (did you see I had a 7 segment display upside down...). :wink:
Above, I wrote:
I have some minor interference between the crystal and the place where the ISP header goes
As it turns out, the interference is less than I originally thought. All I need to do is raise the header 1/64th inch (.4 mm) from the board when soldering. The crystal will then be below the connector.
Chuck-Rowst wrote:
If your airplane has any degree of vibration (like most I am familiar with), you will want to reinforce those "oil tank" capacitors and the crystal with some RTV "potting".
Thanks for reminding me Chuck. I hadn't thought about that yet. I am familiar with the practice. Although one of the touted advantages with using a Corvair engine in an airplane is its smoothness. :wink: It will be nice, since airplanes usually shake like crazy. :shock:
Chuck-Rowst wrote:
Let the programming commence!
YEP! That's what's next! :D A few loose ends on the mechanical stuff and then programming....

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

Last Edited: Mon. Sep 30, 2013 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
joeymorin wrote:
The photo-op on top of the PCB CAD drawings is a nice touch ;)
Thanks JJ, it seems you notice some of the subtle things...
Sometimes...
Quote:
(did you see I had a 7 segment display upside down...). :wink:
Not this time! I see it now. I was going to ask if that was a design feature, but I can see from the traces on the backside that it's not.

I hope you didn't have too much trouble fixing it!

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I hope you didn't have too much trouble fixing it!
The displays were not soldered in place for the photo - I just dropped them into the holes to take the picture. I need to carefully stand them a specific distance above the PCB to have them protrude properly to the front. So no... no problem fixing it, since they still are not soldered yet. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:shock: :evil: :twisted: AAHHRGG!!! :twisted: :evil: :shock:

Murphy strikes again! :? :shock: Well maybe it was really me.... :cry: :oops:

When I did the PCB layout, I forgot that I will be plugging in the ISP from the BACK of the board. So the layout is a mirror image of what I need. :cry:

I suppose I can use the front of the board for now (while I am only programming the 7 segment displays), but I'll probably have to make an adapter for when the two PCBs are stacked together.... :(

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
I suppose I can use the front of the board for now (while I am only programming the 7 segment displays), but I'll probably have to make an adapter for when the two PCBs are stacked together.... :(
It looks like there's enough clearance for a right-angle header. This one is a 3x2, which is a bit taller than this 2x3.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
It looks like there's enough clearance for a right-angle header.
The problem is that the header also takes signals to the other board, so a right angle header won't do the job there. :cry:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The problem is that the header also takes signals to the other board, so a right angle header won't do the job there. :cry:
Oh, noooo....

Did you invert the header placement on the other board as well? I hope so... and judging from the location of the square pad on both boards, it looks like you did.

I suppose an adapter is in order... probably one that lives outside the unit...

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I suppose an adapter is in order...
Agreed. :wink:

I do have some good news though.... :) I have successfully loaded a test program and the MAX7219 display appears to work properly! :shock: I'll spend some more time on it, but preliminary tests are working great. :D So the ISP connector is my only layout error so far. :oops:

I ordered some yellow LEDs that should be here in a few days (along with some 15 pf caps for the xtal). I need to solder in the PCA992 LED drivers and add the yellow LEDs. So it looks like I'll be working on the bar graph code real soon! :wink:

Cris

[edit] After further testing, the 7 segment display portion of the circuit is working perfectly! :shock: :D :lol:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

In my several decades experience in this business I have seen very few perfect 1st Pass PCBs. It seems like there is always something missed - either electrical or mechanical. We strive for perfection, but it rarely happens with 1st p ass PCBs. Consider yourself "blessed" that whatever shortcomings you encounter are fixable to some degree or another. And that the first cut PCB will serve a productive purpose in the overall project development. I have seen too many that were completely unusable and had to be scrapped at great expense of money & project time.

Knowing that to be a simple manifestation of human fallability, I never schedule a production-bound project with just one PCB cut. (Unless it's a simple mod of an existing design.)

My advice is to hold off on ordering sencond rev PCBs until you have "pushed" the first rev boards as far as you can with hardware debug, software development, mechanic mods, and all final tests you intend to perform (e.g. temperature testing). In other words, learn as much as you can from the hitched up rev 1 cards, before you spring for the 2nd revs PCBs. It seems a lot of people tend to go off premature on this and end up buying too many intermediate revision PCBs uneccessarily. Mistakes will be made, you don't need to compound them with misplaced impatience.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
In my several decades experience in this business I have seen very few perfect 1st Pass PCBs.
Yes, I agree. :wink: I have made in the range of 100 PCBs with ExpressPCB over at least a decade or so, I seldom get it 'right' the first time. There seems to always be at least one minor error. :oops:

If I don't find any more errors (or even if I do), I will definitely consider these boards a great success! ExpressPCB's prices and turn around make it so much nicer than the other methods I have used in the past! :wink:

Chuck-Rowst wrote:
hold off on ordering second rev PCBs until you have "pushed" the first rev boards as far as you can
You may have missed it... (I think is was in a previous thread of mine...) but I doubt there will be any more PCBs for this tachometer. I probably won't make any more than this one. If I do, it won't be any more than two more (which is the number of PCBs I already have).

I am not making a product, this is just a one-off for me. There are a lot of 'short cuts' I'm taking that I can get away with since I don't need to be concerned with production. 8)

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Above I wrote:
A few loose ends on the mechanical stuff and then programming....
Those loose ends are almost done. :wink: The bezel is machined from a block of black Delrin plastic. I don't want to have a problem with stripping screw threads so I made some brass inserts. There are inserts for the four 6-32 mounting screws that hold the gauge in the panel, and there are four 2-56 screws to hold the PCB to the bezel. I also added a small radius on the ID of the bezel....

I like the Torx head design for screw drivers and incorporated a similar shape to capture the inserts. You can see the small screws to hold the PCB here:

This is what the inserts look like:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hang on... did you machine those brass inserts yourself? Very nice!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
did you machine those brass inserts yourself?
Yes, but I cheated... :wink: I have a machine shop with some nice machines (it makes it a lot easier).

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow!

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now you are just bragging. Why have two Bridgeports? Isn't one enough?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Now you are just bragging. Why have two Bridgeports? Isn't one enough?
One for meat, one for dairy.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Now you are just bragging. Why have two Bridgeports? Isn't one enough?
If one is good... aren't two better? 8) Yeah... you're right... I'm just bragging. :wink: (I used to have another but I sold it)

The machine on the left (in the back corner) is a Bridgeport Series II and weighs 5000+ lbs. It is a very old N/C (before CNC) machine. It is so old (circa 1975), the controls used REAL TTL discrete logic chips. :shock: I haven't yet converted it to Mach3 and it's partially disassembled. And yes, as JJ says, that's the one for "meat".

The Bridgeport in the back center, is the CNC that I showed in a previous post (above). It is a Series I and is a few years newer. I HAVE converted it to Mach3.

The mill on the right (just past the lathe) is a Bridgeport Series I clone and is a manual machine. That means I actually have to turn cranks to use it.... :shock:

The lathe on the right is a 13" toolroom lathe, and the lathe on the left is an old Logan 10" (like some that were sold by 'monkey ward' back in the day (I inherited it from my grandfather).

Oh, and the green and black mill on the bench is a cheap Chinese benchtop mill (Seig X3) I'm going to convert to CNC for a friend.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

So, which machine is the one you actually used to machine the bezel & inserts? Is it CNC?

When you make mods to the bezel, etc, do you rework an existing one, or simply have the machine run a completely new piece?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
which machine is the one you actually used to machine the bezel & inserts? Is it CNC?
The bezel was done on the CNC (against the wall in the middle in the photo) and the lathe (far right). All the features of the back were done on CNC, the front 'ring' and flange face were done on the lathe. The lathe makes round things nicer than the CNC (the tool marks are circumferential).

The inserts were done on the CNC, manual mill and lathe. The 'lobes' and round boss were done with CNC, the manual mill was used to slice them off the brass block, and the lathe was used to drill and tap.

Chuck-Rowst wrote:
When you make mods to the bezel, etc, do you rework an existing one, or simply have the machine run a completely new piece?
That would depend on what needs to be done. If it is a matter of removing more material, then a rework is in order. If material needs to be added, well since machining is a removal process, a new one is made.

So far, I haven't needed to make any mods. 8) Computer modelling is a big help in that regard. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Above I wrote:
the yellow LEDs that I have claim to be amber, but they are somewhere between orange and red. :? I'll need to get some that are really yellow.
I got new yellow LEDs yesterday and soldered them in place. This is the bar graph display board:

The yellow LEDs are a different package and are taller:

The taller LEDs need to fit into the diffuser:

So I had to modify the slots to fit the new LEDs.

You can see the second, third, and forth slots (from the left) are now deeper. :wink: Next is to hook up the bargraph PCB with some temporary leads to test all the functions with a test program before it is permanently assembled with the other PCB. Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

Last Edited: Thu. Dec 18, 2014 - 07:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have been experimenting with the 7 segment display and the MAX7219. The chip is getting really HOT, so I re-read the data sheet to make sure I selected the proper Rset value.

The data sheet does not make sense.... On page 10, it says:

The current per segment is approximately 100 times the current in ISET. To select RSET, see Table 11.

QUESTION:
If the MAX7219 is a current source, why would it care about the LED forward voltage?

I would guess that Rset is part of a feedback loop, so it should also have no correlation to the LED.

On top of all that, if I want 10mA with a 1.5 V forward voltage, the table indicates 66.7 ohms. At least that is how I read it. :? I have an old project from the early '90s that has MAX7219s so I looked to see what it used.... It's 10K! :shock:

Does anybody know what is REALLY going on with MAX7219s? :?

Cris

Attachment(s): 

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:

The data sheet does not make sense.... On page 10, it says:
The current per segment is approximately 100 times the current in ISET. To select RSET, see Table 11.

QUESTION:
If the MAX7219 is a current source, why would it care about the LED forward voltage?

I would guess that Rset is part of a feedback loop, so it should also have no correlation to the LED.

What I think happens is that some current flows from +5V through Rset into ISET, then to the base of an internal NPN that controls the segment current. The base of that NPN is about 0.7V above the LED voltage drop, so the current flowing through Rset depends on that voltage drop.

Quote:

On top of all that, if I want 10mA with a 1.5 V forward voltage, the table indicates 66.7 ohms. At least that is how I read it. :? I have an old project from the early '90s that has MAX7219s so I looked to see what it used.... It's 10K!

It should be 66.7 kohms for 10mA. No wonder your max7219 is getting hot!

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mnehpets wrote:
It should be 66.7 kohms for 10mA.
I did some experimenting. I installed a 5k resistor, a 10k and a 20k resistor and checked the voltage drop of each resistor. With the 5k, the voltage across the resistor was 3.25 V, with the 10K it was 3.55 V, with 20k it was 3.82 V.

According to Ohm, current with the 5k is .65 mA, 10k is .36 mA, and 20k is .19mA. So then the LED current is supposedly 100 times that, or 65 mA, 36 mA, and 19 mA, respectively.

This still seems to have little correlation with Table 11. :shock:

[edit] I am shooting for 15 mA nominal, so I used a 33.2k and 100k in parallel (since I don't have many values in my stock - it comes to 24.9k) and that calculates to 15.9 mA to the LEDs. :wink:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
QUESTION: If the MAX7219 is a current source, why would it care about the LED forward voltage?
The datasheet makes no mention of a constant current source. Neverthess, the relationship between Rset and segment current is relatively flat across a wide range of LED Vf. Looking just at the first row of the table, Rset ranges between 9K69 and 12K2, a ratio of about 4:5 (80%), over a range of Vf spanning 1.5V to 3.5V, a ratio of 3:7 (43%).

aeroHAWK wrote:
On top of all that, if I want 10mA with a 1.5 V forward voltage, the table indicates 66.7 ohms.
The table is a bit misleading. Values are in KΩ, not Ω.

aeroHAWK wrote:
With the 5k, the voltage across the resistor was 3.25 V
In the datasheet, Maxim wrote:
[the resistor's] minimum value should be 9.53kΩ, which typically sets the segment current at 40mA.

aeroHAWK wrote:
According to Ohm, current with the 5k is .65 mA,
Which would imply a 65 mA segment drive, beyond the device's recommended maximum.
Quote:
10k is .36 mA,
That falls into the table's first row for 40 mA, and 100 x 0.36 mA is pretty close to 40 mA.
Quote:
20k is .19mA
Row 3, 20 mA, pretty close to 100 x 0.19 mA.

aeroHAWK wrote:
This still seems to have little correlation with Table 11.
In the datasheet, Maxim wrote:
nominally 100 times
... and remember that it's not a constant current device.

aeroHAWK wrote:
[edit] I am shooting for 15 mA nominal, so I used a 33.2k and 100k in parallel (since I don't have many values in my stock - it comes to 24.9k) and that calculates to 15.9 mA to the LEDs. :wink:
Experimentation is probably your best bet, since the 7219 isn't a constant current device.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the perspective JJ.

joeymorin wrote:
The table is a bit misleading.
Nowhere does it indicate kOhms.
joeymorin wrote:
In the datasheet, Maxim wrote:
[the resistor's] minimum value should be 9.53kΩ, which typically sets the segment current at 40mA.
I somehow missed this. :oops: This is the only clue that might point to the table being kOhms.
joeymorin wrote:
Quote:
10k is .36 mA,
That falls into the table's first row for 40 mA, and 100 x 0.36 mA is pretty close to 40 mA.
Quote:
20k is .19mA
Row 3, 20 mA, pretty close to 100 x 0.19 mA.
Yes, but I still stick with what I wrote:
This still seems to have little correlation with Table 11.
Because the resistor values are quite a ways off. :roll:
joeymorin wrote:
Experimentation is probably your best bet
Yes, I agree! I would have hoped the datasheet would have been more definitive or specific.

Again thanks JJ. Your comments have given me more understanding about what the datasheet (however vague) is attempting to convey. 8)

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
joeymorin wrote:
The table is a bit misleading.
Nowhere does it indicate kOhms.
Neither does it say 'Ohms'. That's what makes the table misleading ;)

However, every reference to a value for Rset elsewhere in the datasheet is for a value expressed in KOhms. Small comfort :)

Quote:
Yes, but I still stick with what I wrote:
This still seems to have little correlation with Table 11.
Because the resistor values are quite a ways off. :roll:
The conclusion that the values are 'way off' would be valid if Rset configured an internal constant current circuit. It doesn't, because there isn't one. The table is your only guide.
Quote:
joeymorin wrote:
Experimentation is probably your best bet
Yes, I agree! I would have hoped the datasheet would have been more definitive or specific.
Might be worth submitting an errata report to MAXIM.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

How are you determining that there is poor correllation between the segment current and the Rset value?

Did you see the graph at the upper right corner of page 4 in the data sheet? Does this match your observations beter than the values given in the table?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
The conclusion that the values are 'way off' would be valid if Rset configured an internal constant current circuit.
I want 15 mA segment current. The table suggests 48 kOhms for Rset. Actual is 24 kOhms.... yes, I consider this WAY OFF. :shock: I don't see that it matters if it is a current source or voltage source or frustration source. :wink:
Chuck-Rowst wrote:
Did you see the graph at the upper right corner of page 4 in the data sheet? Does this match your observations beter than the values given in the table?
If I understand what the graph is telling me... it is 10-15% off. It seems to be closer than the table but I am not entirely clear what the graph is for. :?

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
yes, I consider this WAY OFF. :shock:
Quote:
If I understand what the graph is telling me... it is 10-15% off.
Silly question, but are you measuring average current or peak current?

Also, you should consider the possibility that you've cooked the 7219 by experimenting with an Rset of 60 ohms.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All props to you Cris, you're a master craftsman ! With the CLEANEST machine shop I've ever seen ( You know you cleaned up before taking that pic :wink: )! Why do the inserts have a "star" shape...I'd guess there are other shapes ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
are you measuring average current or peak current?
I assume it's average current since I'm using a DVM (even so, I measured at max intensity so average and peak should be pretty close - if there is even a difference in the first place).
joeymorin wrote:
you should consider the possibility that you've cooked the 7219 by experimenting with an Rset of 60 ohms.
Yes that's possible... however all 4 digits behave the same and they all respond to the onboard PWM just fine.
indianajones11 wrote:
All props to you Cris, you're a master craftsman ! With the CLEANEST machine shop I've ever seen ( You know you cleaned up before taking that pic :wink: )!
Well close... I have recently relocated my shop into a new building and the photo was taken right after painting the floor and walls and the machines were set in place (if you look at the shelves behind the wall on the left, you'll notice I haven't filled them yet :wink: ).
indianajones11 wrote:
Why do the inserts have a "star" shape...I'd guess there are other shapes ?
They need a flange so they don't pull out, and the star shape is so they don't rotate. I could have made them square or hex, but as I mentioned, I like the star shape of Torx drivers so I used something similar.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
joeymorin wrote:
are you measuring average current or peak current?
I assume it's average current since I'm using a DVM (even so, I measured at max intensity so average and peak should be pretty close - if there is even a difference in the first place).
Sorry, I was referring to the fact that this is a multiplexing device. Are you driving all digits of the segment you are measuring? Even if you are, remember that there is an inter-digit blanking period, so a DMM will read a lower current than is the actual peak current, and the datasheet specifies values of Rset for peak current.

The blanking time is set by the intensity register. Maximum intensity is 31/32 of a cycle, for a blanking period of 1/32 of a cycle. The default power-up state of the intensity register is for the minimum intensity of 1/32 of a cycle, and a blanking time of 31/32 of a cycle.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

So, where exactly are you connecting the DVM to measure or determine the segment current? Also, what values are you loading into the 7219's configuration registers?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I was referring to the fact that this is a multiplexing device.
Chuck-Rowst wrote:
where exactly are you connecting the DVM to measure or determine the segment current?
Thank you JJ and Chuck for your persistence to get through my arrogance and stubbornness! :shock: I get it now.

You have helped me see the error in my approach. :oops: My conclusion that the datasheet is wrong is based on erroneous assumptions. :oops: And I have been reminded of something I have said in a previous post... that I know "just enough about electronics to be dangerous". :shock:

Now I see it is very likely that the datasheet is accurate. :oops:

Soooooo... as it turns out, I don't really care what the LED segment current is. :? What I DO care about is how the display LOOKS (I was only guessing the 15 mA per segment would do it). So based on that, I can experiment with Rset to achieve what I am after. The actual number is not real important (as long as it doesn't damage the chip or LEDs :wink:).

You have helped me understand the datasheet so now I have a much better understanding of the MAX7219. :)

THANKS again!

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

In any of the 94 above posts did you describe the power supply you are using for this tachometer? What is the voltage available on your aircraft? How do you convert it to the voltages needed in your circuitry (3.3? 5.0? )?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
In any of the 94 above posts did you describe the power supply you are using for this tachometer?
No I have not.
Chuck-Rowst wrote:
What is the voltage available on your aircraft? How do you convert it to the voltages needed in your circuitry (3.3? 5.0? )?
The airplane will have an electrical system similar to a car - 12 V nominal. I will have a 12-5 V DC-DC power supply and have a separate 5 V bus for the gauges I make. The only place I will need 3.3 V is for the MAX31855s for Temp gauges, and that will be done internally to the gauge (along with associated level shifting needed).

[edit] corrected MAX31855 (was MAX3155)

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

Last Edited: Wed. Oct 9, 2013 - 06:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
Soooooo... as it turns out, I don't really care what the LED segment current is. :? What I DO care about is how the display LOOKS (I was only guessing the 15 mA per segment would do it). So based on that, I can experiment with Rset to achieve what I am after. The actual number is not real important (as long as it doesn't damage the chip or LEDs :wink:).
Yup!

It means, of course, that you're going to have to look at another datasheet ;) ... the one for the LED. It also means that you have to determine the true peak current delivered by the 7219. An oscilloscope will come in handy. You can measure average current with a DMM, and observe the waveform on the 'scope to estimate duty cycle. This will allow you to calculate peak current.

You really want to make sure that you stay below the peak current rating for the LEDs, as well as the max average current rating. Surpassing those limits will result in cumulative damage to the LEDs that will eventually lead to failure.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

So there's no voltage regulator in the tachometer itself, everything runs off the bussed 5 volts, correct?

How much current are you expecting the completed tachometer to draw from the 5 volt bus under worst case operating conditions (I'd image at full-brightness) ?

You stated:

"The actual number [ ma per segment ] is not real important as long as it doesn't damage the chip or LEDs"

Agreed. But how will you know how "hard" you are driving the chip and how close it is to self-destruction? My advice would be to monitor the temperature of this chip in the fully assembled unit operating under the worst case brightness scenario. Then use this temperature to calculate the chip's die temperature based on thermal parameters given in the 7219's data sheet. The die temperature is directly related to statistically expected lifetime of the chip. ( The hotter the die the less the expected lifetime. There's an exponential relationship between the two commonly expresses as: "A halving of expected life (i.e MTBF hours) for every 10 deg C increase in die temperature. )

Also, the maximum power dissipation of the 7219 (how much heat it must shed to drive the LEDs) may not occur at maximum LED brightness, it may occur at somewhere closer to 75% LED bightness.

My EE instinct tells me I'd be more concerned in this design with burning up the 7219 rather than burning up a segment of the display.

While you may not need to know the exact peak or average current of the segements so long as you get the aesthetically & ergometrically correct display brightness, IMHO you also want to make sure you are not running the 7219 on the ragged edge of self-destruction.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
It means, of course, that you're going to have to look at another datasheet ;) ... the one for the LED.
joeymorin wrote:
You really want to make sure that you stay below the peak current rating for the LEDs, as well as the max average current rating.
The LEDs are HDSP-7303, max peak 150mA, average 25mA. Since I now understand more about the MAX7219 data sheet, I can make an educated guess at the peak current based on number of displays and Rset current. It seems difficult to get near the 150mA limit with my current setup. :wink: Also, since increased LED brightness rolls off at higher average current levels, there is a point of diminishing returns. My understanding is that if I stay below this area of 'diminishing returns' the LEDs will not be stressed. I can see this by watching the amount the brightness changes with different levels of intensity from the MAX7219 PWM.
Chuck-Rowst wrote:
how will you know how "hard" you are driving the chip and how close it is to self-destruction?
My gut sense is to check that the MAX7219 is not hot... It's not. :wink:
Chuck-Rowst wrote:
So there's no voltage regulator in the tachometer itself, everything runs off the bussed 5 volts, correct?
Correct.
Chuck-Rowst wrote:
How much current are you expecting the completed tachometer to draw from the 5 volt bus under worst case operating conditions (I'd image at full-brightness) ?
500mA to 600mA.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like those little TI switchers that have 3 terminals like a 7805. Wide input range 9-32 I think.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
I like those little TI switchers that have 3 terminals like a 7805. Wide input range 9-32 I think.
Yes, I think I have some... they can handle up to 2 amps. :wink: I've had these for many years, they're made by PowerTrends (I understand TI bought them out).

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

Yes, you are correct, in general if the driver chip doesn't feel hot there is likely no danger of self-destruction. Still, let me make ask another question...

I have had experience with cockpit instrument design. One of the big issues is "sunlight readability". I am not a pilot, so I don't have direct experience with this issue. But I have had to deal with instrument lighting specs that require "sunlight readability".

Back in the old days of mechanical instruments apparently sunlight readability wasn't much of an issue. About the only sunlight readability issue was glare off of the instrument's cover glass. With today's LCD and LED instruments things are different.

LCD displays have one set of issues and LEDs another. To achieve sunlight readability with LEDs you need to drive the LEDs super-hard. We had a special theatrical spotlight we used to simulate the level of direct sunlight coming into a cockpit. LED drive levels which would seem "very bright" in a well lit office, were completely washed out when subjected to the stage light's simulated sunshine.

We frequently found that we were pushing the upper current limits of the LEDs (often 7 segment or British Flag types) and that the consequent total power requirements of the instrument presented design challenges of their own. At that time there was only a limited selection of LED displays that were actually suitable for cockpit use. I'm sure the choice is much wider today. Plus, we have much more efficeint LEDs.

So, you may want to keep this in mind and do a little sunlight testing before you settle on a specific LED drive level and the various codependent design parameters & decisions.

If your current consumption is only 300 to 500 mA at 5 volts, the power dissipation of your tachometer will be around 2 to 2.5 watts. Overall, you shouldn't have any overheating issues with an instrument of this volume, even in an enclosed cockpit on a hot summer afternoon.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
LCD displays have one set of issues

And then along comes a pilot wearing a pair of polarized sun glasses...

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
I have had to deal with instrument lighting specs that require "sunlight readability".
Chuck-Rowst wrote:
Back in the old days of mechanical instruments apparently sunlight readability wasn't much of an issue. About the only sunlight readability issue was glare off of the instrument's cover glass.
I have thought about this. I don't expect sunlight readability, at least not direct sunlight. My thinking is this; when 'in the old days' as you say, with glare off of the instrument's cover glass, you would shade the instrument with your hand to read it. I expect the same here. Also, when the sun is shining like that, it is usually because the weather is good. In good weather, the need for instruments is lower - just fly by looking out the window. :wink: A tachometer is far less critical than other instruments so a little inconvenience in reading doesn't seem like a major deal to me (and there are other cues to enable the pilot to set RPM). The radio in my car has sunlight readability issues and occasionally I need to shade it with my hand, so it is something I have dealt with.
Chuck-Rowst wrote:
you may want to keep this in mind and do a little sunlight testing
Thanks Chuck, I will.
Chuck-Rowst wrote:
Overall, you shouldn't have any overheating issues with an instrument of this volume, even in an enclosed cockpit on a hot summer afternoon.
Part of avionics installation involves providing adequate cooling air behind the panel. Many times there is a vent that directs a blast of outside air to the avionics. Also, when the MAX7219 was running so hot, I had designed a heat sink for the rear cover of the tach. I could still use it if needed. :wink:
DocJC wrote:
And then along comes a pilot wearing a pair of polarized sun glasses...
Yeah, that's a whole different issue. Fortunately, I don't need to deal with it here. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you are flying indoor the fluorescent lights can be a pain...

Sometimes a good old fashioned glare shield is a wise approach.

JC

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
When you are flying indoor the fluorescent lights can be a pain...
LOL. Well at least they aren't as bright as the sun... 8)

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many of you may remember this PCB I started with in my AVR education.

I have three of them. One of them has just the ATtiny26 soldered in. I've used it as a pulse source to simulate my tachometer input, along with other stuff. I tack soldered leads to it and to the bar graph display board. This way I can test the bar graph circuit with a test program before I assemble the bar graph and 7 segment PC boards together.

After spending a few hours getting past some bonehead errors (I wasted a lot of time before I discovered I loaded the WRONG program into the AVR :oops: and I left the enable pins floating so I added a pull-down resistor)....
:D :lol: IT WORKS! :lol: :D

The LEDs are nice and bright so they washed out the whole photo. :shock:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very nice!

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Jay. :wink: It is always a big relief when I get a new PC board working for the first time. 8) Since I don't consider myself an electronics type, I worry that my ignorance may bite me now and then. So far I've been pretty lucky. :P

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What will the led and rpm refresh rate be? Will you be able to post a video of the led tower and the rpm digits at the same time?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
What will the led and rpm refresh rate be?
The LED tower will refresh at 80 Hz. The digital display is subject to the MAX7219 and I don't recall it's frequency. :?
bobgardner wrote:
Will you be able to post a video of the led tower and the rpm digits at the same time?
Unfortunately I do not have a way to get video. :cry: I don't use a smart phone and I have no other video camera.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The digital display is subject to the MAX7219 and I don't recall it's frequency.
6400/N where N is the number of digits you're multiplexing. You're using 4, so that should be 1600 Hz.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's fast enough to not flicker on a video. Ask a buddy with a smartphone to record a sweep up sweep down with a pot. Yo Doc: I assume that was simulator, because there seemed to be more lcds than round gauges. Any idea who made it? As for full sunlight readability, I remember something like 1200 nits (candelas per sq meter). Wasn't that informative? Real Bright would have been about as good.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK,

Looks very nice!

Are you at a point in your code where you can load any "value" into the bar graph? Or, can you only load the complete bar?

With this type of display it's usually a good idea to write a simple test routine that "pumps" the display. That is, it sends successive loads to the shift registers that makes the display grow from one segment per load up to its full size, then back again. It's a pretty cool way to show off your handiwork, but also serves the purpose of uncovering various faults and deficiencies in the display. E.g. Shorted segments or length-dependent brightness issues.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
Looks very nice!
Thanks Chuck!
Chuck-Rowst wrote:
Are you at a point in your code where you can load any "value" into the bar graph? Or, can you only load the complete bar?
Only the complete bar.

From here, I will be doing the programming in steps:

    1. Get both bar graph and 7segment to light all segments 2. Program bar graph to display any value (500-4000 rpm)
    3. See if I can combine bar graph and 7 segment routines
    4. Use Timer0 to time RPM counting
    5. Configure ADC to 'read' dimming signal level
    6. Set up Timer1 for bar graph dimming PWM
    7. Figure out bar graph top lit segment PWM
Numbers 1 & 2 are self explanatory.

For number 3, the MAX7219 and PCA9922s use the same clock. The MAX7219 gets two data bytes in each packet but the PCA9922s get just one. At first there will be separate routines for each, but then I want to combine them so the PCA9922s get their data byte at the same time as the MAX7219 gets its first byte.

Item 4 is basically changing from Timer1 to Timer0 to free up Timer1 for the bar graph dimming PWM. In the ATtiny26, Timer0 has no compare feature and Timer1 is the only PWM. My previous program uses Timer1 for the RPM timing, so I need to make sure I can figure out using Timer0.

The 5th step is to read the value of an external voltage level that will control the overall dimming for various light conditions.

Number 6 should be self explanatory and 7 is to adjust the brightness of the top lit bar graph segment proportional to the fraction of 100 RPM left from the other lit segments.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have now completed all the electronics assembly. :D :o :lol: :P

This is what it looks like all together:


I need to cut a hole for the connector in the metal can that covers the back:

Then all that remains is SOFTWARE. :shock:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, briefly off topic:

Quote:
Yo Doc: I assume that was simulator

Nope, this was an American Eurocopter EC130, in an air medical configuration. The real deal, not a sim. This photo is the same aircraft, (I think. Its my photo, but I have 100's of copter photos...).

The National Flight Physician's conference is in two weeks. Guess where I'll be! (Actually it will all be classroom continuing education, no flight time, but there will be a number of aircraft on display).

A very nice looking aircraft, but pretty small for the job, by my thinking.

JC

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow! Very nice.

Actually incredibly nice. As much as I like photos, (one pic's worth a thousand words...), I won't show you any of my cases. Complete with hand written taped on labels, drill skidding across the case skuff marks, missing display benzels, etc.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
... hand written taped on labels, drill skidding across the case skuff marks, missing display benzels, etc.
Sounds like most of my projects... ;)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
Wow! Very nice.
Thanks Jay. :wink:
DocJC wrote:
hand written taped on labels, drill skidding across the case skuff marks, missing display benzels, etc.
Yeah, I have some like that too... :shock: (but you'll notice I'm not posting pictures of them either). :wink:

I have finished item number 1 of my list (above):

I have to say, this image doesn't do it justice. :wink: When I first turned everything on, it was impressive! I am VERY happy with the results.... :P

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Gorgeous !!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck-Rowst wrote:
Gorgeous !!!!
Thanks Chuck. :)

I'm now wrestling with what it takes to control the bar graph. The parallel data lines are making my head hurt since it is something I have never done before.... :? It's a lot of stuff to keep track of. :shock: At least for me. :oops: I'm also dealing with making sure the MAX7219 and PCA9922s don't confuse each other (since they have a common clock). My programming inexperience is rearing its head... I found some bonehead errors in my bit-banging code. :shock: :oops:

I AM making progress though. :wink: It's really neat to be past the construction phase and on to the programming phase.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Above, I wrote:
I will be doing the programming in steps:
    1. Get both bar graph and 7segment to light all segments 2. Program bar graph to display any value (500-4000 rpm)
    3. See if I can combine bar graph and 7 segment routines
    4. Use Timer0 to time RPM counting
    5. Configure ADC to 'read' dimming signal level
    6. Set up Timer1 for bar graph dimming PWM
    7. Figure out bar graph top lit segment PWM
I have now completed Items 1, 2, and 3. :P

With separate routines for the MAX7219 and PCA9922s, for some reason (that I haven't determined), the MAX7219 routine would interfere with the PCA9922s. Although they all have a common clock, the latch lines are on separate ports :shock: and they are not supposed to be active at the same time. :? This is the pinout (as posted above):

//==============================================================================
//                                                                             |
//                          ATtiny 26 Microcontroller                          |
//                                                                             |
//                                 +----v----+                                 |
//        MAX7219 Load   MOSI/PB0 -| 1    20 |- PA0/ADC0  Analog Dimmer Input  |
//    MAX7219 Data Out   MISO/PB1 -| 2    19 |- PA1/ADC1  PCA9922 Load         |
//        Serial Clock    SCK/PB2 -| 3    18 |- PA2/ADC2  PCA9922 Data Out A   |
//    BarGraph Dim Out   OC1B/PB3 -| 4    17 |- PA3/AREF  Capacitor to ground  |
//                            VCC -| 5    16 |- GND                            |
//                            GND -| 6    15 |- AVCC                           |
//      16 mHz crystal  XTAL1/PB4 -| 7    14 |- PA4/ADC3  PCA9922 Data Out B   |
//      16 mHz crystal  XTAL2/PB5 -| 8    13 |- PA5/ADC4  PCA9922 Data Out C   |
//  Crank Sensor Input   INT0/PB6 -| 9    12 |- PA6/ADC5  PCA9922 Data Out D   |
//               Reset  RESET/PB7 -| 10   11 |- PA7/ADC6  PCA9922 Data Out E   |
//                                 +---------+                                 |
//                                                                             |
//==============================================================================

Instead of spending the time to find the problem, since I planed to integrate them together, I went straight to the integration. 8)

It had its challenges though. The MAX7219 needs a two byte data packet and the PCA9922s only one, so I had to manage that. I got lucky and it worked the first attempt. :wink:

So I have the bar graph incrementing 100 rpm every half second, as the digital display shows the actual number.

It is humorous that I can be so entertained by flashing colored lights.... :shock: :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Above, I wrote:
I need to cut a hole for the connector in the metal can that covers the back
I've done that now. :D Here is what the completed gauge looks like all assembled:


So all I need to do is finish the software. 8)

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's just gorgeous!

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
That's just gorgeous!
Thanks JJ! :wink:
JohanEkdahl wrote:
Close by was a photo of the actual workshop. By Golly! DocJC could perform open heart or brain surgery in there. That has got to be the neatest place I've ever seen!
Thanks Johan, but to be fair, the shop hadn't been used yet. I had just relocated to that space, the photo was taken just after the machines were set in place. I am in the process of remodeling the building to suit my specific needs (to see more, I have a web page that shows what I'm doing here - click on 'Shop' on the left side of the page). I hope to have it organized well enough to keep it clean. :wink:
JohanEkdahl wrote:
Since this thread is closing in on the finishing line (or at least the instrument is), let me tell you how much I have enjoyed this. Something being built from scratch and ideas and sketches to the finished hardware and soon software. And the end result hardware-wise is just as fine as the initial sketches hinted at.
I know that I enjoy seeing interesting projects that people do. I hoped that this would be something others would be interested in. Thanks for letting me know that you are. :wink: Also, I want all you "Freaks" to know that I couldn't have done this without you all! :!: This is my way of letting you all see the result of your contributions, and to express my thanks.
JohanEkdahl wrote:
If I had a hat on it would be off. Thank you very much!
Thanks again Johan! I also appreciate all your assistance!

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am very jealous Cris. That is a magnificent workshop!

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:
I am very jealous Cris. That is a magnificent workshop!
Thanks Ross! Comments like this help me keep from taking it for granted. I feel very fortunate to have such a nice place to do my work. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thus far, this thread has been mostly about the mechanical hardware and the way it all comes together. Since that is all finished, the software is what's left. Since I'm not a software guy, I am running into some obstacles that some of you may help me get past. :wink:

I have some questions:

The top lit segment of the bar graph is PWMed with 8 levels of brightness. The update frequency of the bar graph is 80 Hz, with 8 levels of PWM. So the PWM frequency is (8 x 80) 640 Hz. Timer0 on the ATtiny26 has some limitations so the interrupt frequency is 1280 Hz.

Is there an easy way to divide the frequency in half? If it were hardware, triggering a flip-flop will halve the frequency, so I am wondering if there is a software equivalent?

Another question I have is more complicated to explain. I am looking for assistance in structuring the PWM routine....

The PWM duty cycle is a variable from 0 to 7. With a loop from 0 to 7, what is a simple way to determine which steps of the loop will turn on the LED an which will not?

Also... the bar graph shift registers are all loaded along with the shift register in the MAX7219. However, the MAX7219 gets two bytes while the bar graph gets only one. Plus, the MAX7219 needs two bytes for each of four digits and two more for intensity. So the PWM loop needs to keep track of the MAX7219 data as well as the bar graph data.

So that's 8 bytes to send to the bar graph (for the PWM) and 10 bytes to send to the MAX7219. Any suggestions???

Thanks!

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The top lit segment of the bar graph is PWMed with 8 levels of brightness. The update frequency of the bar graph is 80 Hz, with 8 levels of PWM. So the PWM frequency is (8 x 80) 640 Hz. Timer0 on the ATtiny26 has some limitations so the interrupt frequency is 1280 Hz.

Is there an easy way to divide the frequency in half? If it were hardware, triggering a flip-flop will halve the frequency, so I am wondering if there is a software equivalent?

Use a flag at the top of the ISR:
ISR(TIMER0_OVF0_vect) {
  static uint8_t division_flag = 0;
  division_flag ^= 1;
  if (division_flag) {
    return;
  }
  // your code here
}

Quote:
Another question I have is more complicated to explain. I am looking for assistance in structuring the PWM routine....

The PWM duty cycle is a variable from 0 to 7. With a loop from 0 to 7, what is a simple way to determine which steps of the loop will turn on the LED an which will not?

Your user code sets a PWM level for the LED. Your PWM routine maintains a clock, then compares the level against the clock:
volatile uint8_t pwm_level;

// called only from ISR
void pwm_routine() {
  static uint8_t pwm_clock = 0;
  if (pwm_level && (pwm_level <= pwm_clock)) {
    // your code to light the LED
  }
  else {
    // your code to extinguish the LED
  }
  pwm_clock = (pwm_clock + 1) % 8;
  // any other code you need to handle PWM
}

This will give you 7 levels of different brightnesses, plus 'off'. If you want to forego the off state:

  if (pwm_level <= pwm_clock) {

Quote:
Also...
.
.
.
Any suggestions???
What have you got so far?

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Use a flag at the top of the ISR
Thanks JJ. :wink: I thought of a flag, but it's the XOR that I hadn't....

Another thought I just had is to just use the faster frequency and use a 16 level PWM. :shock: I will still have plenty of time to execute the code.

joeymorin wrote:
Your user code sets a PWM level for the LED. Your PWM routine maintains a clock, then compares the level against the clock
YEP! Again, it's along the lines I was thinking but I just couldn't connect all the dots. :? Your code example is VERY HELPFUL!
joeymorin wrote:
What have you got so far?
Well, since I'm now thinking of using 16 levels of PWM (rather than eight), my general idea is to make a loop to send the first and second MAX7219 bytes of the 4 digits with the first 8 bar graph bytes, then repeat the first and second bytes of the intensity for the remaining bytes.
send bar graph PWM byte 0 and MAX7219 digit1 first byte
send bar graph PWM byte 1 and MAX7219 digit1 second byte
send bar graph PWM byte 2 and MAX7219 digit2 first byte
send bar graph PWM byte 3 and MAX7219 digit2 second byte
send bar graph PWM byte 4 and MAX7219 digit3 first byte
send bar graph PWM byte 5 and MAX7219 digit3 second byte
send bar graph PWM byte 6 and MAX7219 digit4 first byte
send bar graph PWM byte 7 and MAX7219 digit4 second byte
send bar graph PWM byte 8 and MAX7219 intensity first byte
send bar graph PWM byte 9 and MAX7219 intensity second byte
send bar graph PWM byte a and MAX7219 intensity first byte
send bar graph PWM byte b and MAX7219 intensity second byte
send bar graph PWM byte c and MAX7219 intensity first byte
send bar graph PWM byte d and MAX7219 intensity second byte
send bar graph PWM byte e and MAX7219 intensity first byte
send bar graph PWM byte f and MAX7219 intensity second byte

Repeating the intensity bytes may be redundant, but it makes it so I don't need a different subroutine. :wink:

So changing to 16 levels of PWM relieves the need to halve the frequency as well as it provides a simpler way to feed the data to all the shift registers (including the MAX7219's). So I think that's what I'll do! 8)

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
So I think that's what I'll do! 8)
Seems like you've got it under control... ;)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Seems like you've got it under control... ;)
It is interesting how a problem (or problems) can seem almost insurmountable, but then a simple suggestion can alter perception in a way that make things so much simpler! That's what you've done for me JJ!

I had made the problem so big in my head. Then you point me to a simple solution. THANKS! :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had to put this project on hold for a few weeks to get some other work done. :(

But now I'm back to it for a little while. :wink: I've made a small change in my approach....

Earlier I wrote:
I want to switch from timer1 to timer0 for the RPM timer.
In response mnehpets wrote:
You might be able to use timer1 for both PWM dimming and RPM counting
As a reminder, joeymorin wrote:
Just remember that if you're mixing two PWM signals to drive one display element, you must be mindful of 'beating'.
After which, Chuck-Rowst wrote:
The solution would be to somehow co-ordinate the 9522 loading with the PWM dimming signal.
I have since gotten much more comfortable with my understanding of the timers. I discovered that it is really easy to use Timer1 for everything I need. This also synchronizes the PWMs so I won't need to deal with any potential 'beat' frequency issues. :wink:

But this is bringing up some concerns. :? I have found (using the simulator) that each interrupt takes something like 33 clock cycles to simply increment a count. :shock: With both the timer interrupt and tachometer interrupt, there seems to be a lot of unnecessary 'wheel spinning'. It looks like it can have an adverse affect on the accuracy and consistency of the RPM count.

This is from the .lst file from the compiler. I don't understand assembly well enough to know what it is doing.

(0134) //**********************************************************************
(0135) //***************************** TIMER1 ISR *****************************
(0136) //**********************************************************************
(0137) #pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
(0138) void timer1_ovf_isr(void)
(0139) {
(0140)   tick++;
    00109 9180 0061 LDS	R24,tick
    0010B 5F8F      SUBI	R24,0xFF
    0010C 9380 0061 STS	tick,R24
(0141)   start = 1;                      //set start flag
    0010E E081      LDI	R24,1
    0010F 9380 0060 STS	start,R24
    00111 9189      LD	R24,Y+
    00112 BF8F      OUT	0x3F,R24
    00113 9199      LD	R25,Y+
    00114 9189      LD	R24,Y+
    00115 9518      RETI
_int0_isr:
    00116 938A      ST	-Y,R24
    00117 939A      ST	-Y,R25
    00118 B78F      IN	R24,0x3F
    00119 938A      ST	-Y,R24
(0142) }
(0143) 
(0144) //**********************************************************************
(0145) //****************************** INT0 ISR ******************************
(0146) //**********************************************************************
(0147) #pragma interrupt_handler int0_isr:iv_INT0
(0148) void int0_isr(void)
(0149) {
(0150)   tachCount++;
    0011A 9180 0062 LDS	R24,tachCount
    0011C 9190 0063 LDS	R25,tachCount+1
    0011E 9601      ADIW	R24,1
    0011F 9390 0063 STS	tachCount+1,R25
    00121 9380 0062 STS	tachCount,R24
    00123 9189      LD	R24,Y+
    00124 BF8F      OUT	0x3F,R24
    00125 9199      LD	R25,Y+
    00126 9189      LD	R24,Y+
    00127 9518      RETI

Is there a way to streamline what the ISRs are doing?

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:

(0137) #pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF

Is there a way to streamline what the ISRs are doing?

Looks like Imagecraft, with which I have no experience.

Looking at int0_isr(void), I count 21 cycles. The .lst file doesn't seem to show the prologue/epilogue, so I'd guess there is at least another 14 cycles there:

push r24
push r25
in r25, SREG
push r25
.
.
.
pop r25
out SREG, r25
pop r25
pop r24

... but I'm only guessing what Imagecraft does for prologue/epilogue.

Add to that the 6 cycles of interrupt response (not including the interrupted instruction in mainline code) and that's a total of 21 + 14 + 6 = 41 cycles.

If it were GCC I'd suggest writing the ISR in asm (or inline asm). You could easily do the equivalent of:

tachCount++;

in 21-25 cycles in an ISR, +6 for the interrupt response time for a total of 27-31 cycles. If you have between 2 and 4 free I/O registers you could cut that down to about 21/23 cycles.

I/O registers you might consider using (if you don't need them for other things):

    TCNT0 OSCCAL (Since you're running with a crystal. This will affect EEPROM writes. Are you using EEPROM?)
    OCR1A/B/C (Are you using all of these?)
    USIDR (are you still using USI?)
    ADMUX (are you using the ADC?)
If you declare tachCount as a register variable, plus an extra uint8_t variable to save SREG, that could get you down to 14 cycles. Reserving registers for variables will have an impact on the rest of your code, as the compiler won't be able to use them elsewhere. It must be done carefully to ensure a) it doesn't affect performance elsewhere, and b) doesn't break anthing.

Since this is Imagecraft I don't know how to advise you, nor even if any of these approaches are possible. Uncle Bob will be around soon ;)

JJ

[EDIT]
Ah, I was hasty. Looks like the epilogue is there... I was counting it as part of the code (silly!)... and I missed the prologue above the comments.

Curious that Imagecraft uses Y as a stack pointer. I suppose it saves some IN/MOVW/OUT instructions in some cases, but it would seem that it also permanently eats an index register pair in the bargain.

In any case, the total cycle count for your ISR is 28 + 6 = 34 cycles, much closer to what you have observed.
[/EDIT]

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't cover it in my last post, but you could see similar savings in void timer1_ovf_isr(void). Current total is 32 cycles. I expect with assembler, and 1 more (single-byte) register variable, and an I/O register below 0x20 (only 1 bit is needed), you could get this down to 15 cycles.

To get both these ISRs down to these low cycle counts requires reserving 4 of the general purpose registers. As I mentioned, this might not be a win in the end, depending on the reset of your code. Even without register variables, though, you could improve upon the existing code.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
If it were GCC I'd suggest writing the ISR in asm (or inline asm).
Thanks JJ. I'm sure ImageCraft allows this also. I am interested in this. However I am clueless to what the ISR NEEDS to do.
joeymorin wrote:
If you declare tachCount as a register variable,
Can you give an example of how to do this?
joeymorin wrote:
plus an extra uint8_t variable to save SREG, that could get you down to 14 cycles.
This is less than half what is currently happening, so it definately piques my interest. :shock:

Could somebody explain what the ISR has to do so I can get a 'big picture'? And why is the ISR currently doing what it is doing?

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You reserve registers 20,21,22,23 with a tic box in the ide, it links with different libraries that don't allocate those regs. The syntax is in the help file. Also, you might have a GPIOR0 or 1 you could use.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Additional sneakyness can save you an additional 2 cycles by placing the ISR code directly in the interrupt vector table, but this will preclude the use of interrupt sources the vectors for which are supplanted. The INT0 ISR can be as little as 4 words, but that would preclude the use of:

    pin change interrupts TIMER1_CMPA
    TIMER1_CMPB
Similarly, your TIMER1_OVF1 ISR could be as short as 5 words, but that would preclude the use of:
    USI_STRT USI_OVF
    EE_RDY
    ANA_COMP
I'm guessing those aren't the only TIMER1 interrupts you've got? ... so you likely won't be able to use this technique, but it only buys you 2 cycles anyway.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
To get both these ISRs down to these low cycle counts requires reserving 4 of the general purpose registers.
I understand this is a kind of 'cheating', and requires care. I would not be surprised if I have registers available. I am using ADC, USI, and timer1, but not timer0.
bobgardner wrote:
You reserve registers 20,21,22,23 with a tic box in the ide, it links with different libraries that don't allocate those regs. The syntax is in the help file. Also, you might have a GPIOR0 or 1 you could use.
Thanks Bob. I'll take a look! :shock:
joeymorin wrote:
The INT0 ISR can be as little as 4 words
joeymorin wrote:
your TIMER1_OVF1 ISR could be as short as 5 words
I am still clueless as to what I would do with the registers. :? Could somebody give me an overview of what the ISR needs to do?
Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I'm guessing those aren't the only TIMER1 interrupts you've got?
This is Timer1:
//------------------------------------------------------------------------------
//                               SET UP TIMER1
//------------------------------------------------------------------------------
//TIMER1 initialize - prescale:32 & Compare 149 = 3333.333 Hz (300 uSec)
void timer1_init(void)
{
  OCR1B = 0x00;                   //output compare B set to 0
  OCR1C = 0x95;                   //output compare C set to 149 (300 uSec)
  TCCR1A = (1<<PWM1B);            //enable PWM output B (PB3, pin 4)
  TCCR1B = (1<<CTC1) |            //clear on compare
		     (1<<CS12) | (1<<CS11); //F_cpu / 32
}

And other Interrupts:

MCUCR = (1<<ISC00);               //external interrupt detects ANY change
TIMSK = (1<<TOIE0);               //enable Timer0 overflow interrupt
GIMSK = (1<<INT0);                //enable Interrupt0 (PB6 - pin 9)

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
However I am clueless to what the ISR NEEDS to do.
But... you wrote it.

Do you mean you don't know what an ISR needs to do in the prologue/epilogue? It needs to save/restore any GP registers it uses, save/restore SREG if it is modified, restore any stack pointers to their pre-interrupt state, and it must end with a RETI.

Quote:
Can you give an example of how to do this?
In GCC it would be:
register uint16_t tachCount asm ("r2");

Quote:
And why is the ISR currently doing what it is doing?
Here's the existing prologue:
    00116 938A      ST   -Y,R24
    00117 939A      ST   -Y,R25
    00118 B78F      IN   R24,0x3F
    00119 938A      ST   -Y,R24

This saves R24 on the stack (pointed to by Y, which is register pair R28/R29), then R25, then it copies SREG into R24 and saves it onto the stack.

The epilogue undoes this, and ends with a RETI which pops the return address off the hardware stack (different from the Imagecraft R28/R29 user stack), re-enables interrupts, and return to the interrupted code:

    00123 9189      LD   R24,Y+
    00124 BF8F      OUT   0x3F,R24
    00125 9199      LD   R25,Y+
    00126 9189      LD   R24,Y+
    00127 9518      RETI

It does this because the code that actually implements:

tachCount++;

... looks like this:

    0011A 9180 0062 LDS   R24,tachCount
    0011C 9190 0063 LDS   R25,tachCount+1
    0011E 9601      ADIW   R24,1
    0011F 9390 0063 STS   tachCount+1,R25
    00121 9380 0062 STS   tachCount,R24

So R24 and R25 are loaded with the 16-bit tachCount found in SRAM, incremented by 1 (as a 16-bit word), and stored back into SRAM. SREG is potentially altered by ADIW. So the prologue and epilogue must save and restore R24/R25/SREG.

The compiler does all of this automatically. It does a good job, too. However in some cases the programmer can do better.

bobgardner wrote:
Also, you might have a GPIOR0 or 1 you could use.
There are no GPIORn registers in an ATtiny26, but I've listed a few other I/O registers that might be available (depending on what else he's using).

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
joeymorin wrote:
general purpose registers.
I understand this is a kind of 'cheating', and requires care. I would not be surprised if I have registers available. I am using ADC, USI, and timer1, but not timer0.
Those are I/O registers. The sentence from my post you were quoting was in reference to the general purpose registers R0 through R31.

Indeed a solution can include the use of one, the other, or both.

aeroHAWK wrote:
This is Timer1:
So only the two ISRs: INT0 and TIMER1 overflow.

You do use OCR1B and OCR1C for PWM and timer resolution, but OCR1A is available for use in an ISR. So is TCNT0. That's only two. More would be better.

The general idea is that instead of preserving a GP register like R24 by way of:

ST   -Y,R24

... which takes 2 cycles, you use an I/O register with:

OUT   TCNT0,R24

... which takes 1 cycles. A similar savings is seen with the restore.

So for every I/O register you have available, you can save 2 cycles by using OUT/IN instead of ST/LD.

You currently need to save R24/R25/SREG. If you have three available I/O registers, you could save 6 cycles.

If you also used the I/O registers to store tachCount in the first place, you could save another 4 cycles by using IN/OUT instead of LD/ST on each of the two bytes making up the variable.

This would require 5 free I/O registers. You probably don't have that many.

The other alternative I mentioned was reserving GP registers for tachCount and/or the copy of SREG. Doing so means you don't need to load or save tachCount at all, and only need one pair of IN/OUT to preserve SREG (instead of two). So the ISR becomes merely:

IN R4, SREG
ADIW R24, 1
OUT SREG, R4
RETI

This assumes you've declared a uint8_t as a register variable in R4 to store a copy of SREG, and tachCount as a register variable in R24/R25.

[EDIT: corrected invalid register for ADIW]

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Nov 15, 2013 - 06:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I checked to see if there were any new posts just before I hit the "Submit" button on a post I was working on. It turns out you answered the questions I was just about to ask.... :wink:

joeymorin wrote:
OCR1A is available for use in an ISR. So is TCNT0. That's only two. More would be better.
I believe I can use TCNT0, OCR1A, EEDR, and OSCCAL.
joeymorin wrote:
The other alternative I mentioned was reserving GP registers for tachCount and/or the copy of SREG. Doing so means you don't need to load or save tachCount at all
So is this because when using GP registers you know that they won't be changed, but when using I/O registers, you can't be sure?

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
I believe I can use TCNT0, OCR1A, EEDR, and OSCCAL.
I didn't think you could use EEDR because I thought it was like UDRn on devices with a USART i.e. read accesses a different physical register than does write. A simple test program proves me wrong (on the mega328, at least).

So that's 4. That will save you 8 cycles off the bat.

joeymorin wrote:
So is this because when using GP registers you know that they won't be changed, but when using I/O registers, you can't be sure?
Not exactly.

It is up to you to arrange matters such that whatever storage location you use (be it SRAM, I/O register, or GP register) is exclusive. You couldn't for example employ timer 0 for some purpose and also use TCNT0 to store a variable. The timer would continuously update that I/O register whenever the timer was running.

General purpose registers are normally the purview of the compiler. By reserving one or more general purpose registers for use by a single variable, you remove those registers from the pool of registers available to the compiler for implementing the rest of your code.

For simple programs, there may very well be a number of registers that remain unused by the compiler in any way. In such circumstances, you will see no negative impacts of reserving a general purpose register.

In other cases, you might find that the code generated by the compiler for the rest of your program suffers w.r.t. performance because it had fewer registers in which to shuffle data about. Optimising compilers are pretty good about making choices based on available resources. If a temporary copy of a variable is needed, it can be stored more quickly and efficiently in a register than it can in SRAM. If you reduce the pool of available registers, the compiler can't do this as much or as often.

By reserving a general purpose register for use by a variable, you're telling the compiler to never use it for another purpose, even temporarily. This is useful in the context of writing a super-fast ISR, but it may impact the rest of your code.

I/O registers won't change unless the underlying hardware of which they are a part directs that change. TCNT0 won't change, unless timer 0 is running. EEDR won't change unless you fetch a value from EEPROM. OSCCAL won't change ever (except on reset).

Writing in pure assembler gives you ultimate control over all resources on the mcu. But it's harder for most of us :)

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not that I want to stifle your education on assembler, registers, and ISRs, but you may want to take a step back and analyse were the problem lies, exactly.

If you're seeing problems with accuracy from your rpm calculations, you may consider other approaches beyond hand-optimising ISR code.

If the tiny26 had input capture, this would all be a moot point. However, it doesn't :(

The inaccuracies you've observed are due to the fact that you must rely on an interrupt to count the time between pulses from your tach sensor (or pulses per fixed unit time, in your case). Those inaccuracies were always there in the form of interrupt response time and interrupt jitter. In short the timestamp you grab in your INT0 ISR does not reflect the precise moment the sensor triggered interrupt, but the sum of that moment and the interrupt latency.

In your earlier testing that offset was consistent (with jitter of at most 3 cpu cycles), so you probably never saw it.

Now you have a competing interrupt, the one that handles your PWM and display functions. This has the potential to amplify the error you are seeing by adding an unknown and essentially unpredictable additional latency to the 'grab' of the timestamp. If the PWM interrupt is running when the tach sensor triggers the INT0 interrupt, the processing of the INT0 ISR code will be deferred until the PWM interrupt has completed.

Additionally, any other mainline code that accesses shared variable atomically must temporarily disable interrupts to do so.

Instead of whittling away the cycle-count of your ISRs, you may simply want to increase your RPM averaging window. Should be a lot simpler to do.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
The other alternative I mentioned was reserving GP registers for tachCount
joeymorin wrote:
The general idea is that instead of preserving a GP register like R24 by way of:
ST   -Y,R24

... which takes 2 cycles, you use an I/O register with:

OUT   TCNT0,R24

... which takes 1 cycles.

The ISR would still need to increment tachCount, so if an I/O register was used, a few more cycles could be saved....
joeymorin wrote:
By reserving one or more general purpose registers for use by a single variable, you remove those registers from the pool of registers available to the compiler for implementing the rest of your code.
If the saved variable was volatile, wouldn't this be less of an issue?
joeymorin wrote:
In your earlier testing that offset was consistent (with jitter of at most 3 cpu cycles), so you probably never saw it.
Yes, I suppose this spoiled me. :wink:
joeymorin wrote:
Instead of whittling away the cycle-count of your ISRs, you may simply want to increase your RPM averaging window.
Yes, I agree, there is a balance to be found. I know that I am inexperienced and ignorant, so for me to be able to strike that balance, I want to get more educated. Certainly, if speeding up the ISRs is a royal pain, I would forgo the process. So far, I haven't found that to be the case (thanks in large part to you). :wink: When I calculated the 'worst case', I was surprised to find the degree of the error, so I think it's worth exploring options.

I do have a circular buffer to average 10 readings that will smooth out the digital display (along with the possibility of some dead band and/or hysteresis). But the bar graph display will not utilize this as I want to keep it responsive (although it really isn't needed for my specific application - but hey... I'm anal :shock: ).

Thanks JJ, for keeping me from getting lost in the forest... er, :? or the trees.... Your explanation of interrupt response time and interrupt jitter is precisely why I asked these questions and as an engineer, I know it can be easy to get caught-up in the esoteric and loose sight of the real task. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've re-read my posts, and there's a point I didn't really make which you may have not concluded.

Ultimately, any arithmetic must be done on values in the general purpose registers. For example, the ADIW will add a constant value to a register pair. SUB will subtract the contents of one register from another, and store it in that register. LSL will shift all the bits in a register to the left by one bit, and place a zero in the least significatnt bit. In effect, any operation on a piece of data must be done in a general purpose register.

Yes there are exceptions, like SBI/CBI which acts directly on a single bit of an I/O register. There are also tests that don't involve a general purpose register, and other instructions. However, in general the GP registers are involved in any action.

This is why it is valuable to reserve a GP register for exclusive use by a variable. In so doing, you obviate the need to move it from elsewhere into a GP register, and the need to move it back from whence it came.

This is a characteristic of all AVR and some other devices, but not all. The Motorola 6800 and 6809 CPU, for example, allows some direct arithmetic on RAM without the need to use any of the (very limited) general purpose registers. But that's another story.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
any arithmetic must be done on values in the general purpose registers.
Ah ha! That makes sense (and why you would not have suggested using an I/O register). This is an important piece of the puzzle. It helps me understand the reason for GP registers and all the moving of things around.

So I have some studying to do. I need to understand more assembly, and your explanations are a big help! I think I have a good start understanding things so it is a matter of working out some details.

[edit]
Can I assume that when I declare tachCount as a variable register, the compiler will work around it?
Are there rules of thumb as to which registers to use (or does it even matter)?
Oh, and JJ, the syntax you showed should also work in ImageCraft. :wink:
[/edit]

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
You reserve registers 20,21,22,23 with a tic box in the ide, it links with different libraries that don't allocate those regs. The syntax is in the help file.
Above, I wrote:
Can I assume that when I declare tachCount as a variable register, the compiler will work around it?
Are there rules of thumb as to which registers to use (or does it even matter)?
In the help file, I found this (it answers my questions):
Quote:
You can ask the compiler not to use the registers R20, R21, R22, and R23 by checking the Compiler->Options->Target->"Do Not Use R20..R23" option. You should not check this option in general since the compiler may generate larger program because it has less registers to use. You cannot reserve other registers besides this set.

You can access these registers in your C program by using the pragma:

#pragma global_register : :... 

Note that you must still declare the datatypes of the global register variables. They must be of char, short, or int types, and you are responsible to ensure that the register numbering is correct. A 2-byte global register will use the register number you specified and the next register number to hold its content. For example, timer_16 above is an unsigned int, and it will occupy register R20 and R21.

Since these registers are in the upper 16 set of the AVR registers, very efficient code will be generated for them when assigning constants, etc.

Thanks Bob! :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The ISR would still need to increment tachCount, so if an I/O register was used, a few more cycles could be saved....
I think you made this comment before your new-found understanding of the limitations of arithmetic operations and their need for general purpose registers. The advantage confered by the use of I/O registers over SRAM is in the time it takes to fetch/save a variable, not in the time it takes to perform the arithmetic.
Quote:
If the saved variable was volatile, wouldn't this be less of an issue?
Volatile is a high-level-language concept. In C, C++ and other languages declaring a variable as volatile tells the compiler that it should not perform certain optimisations. Specifically, the compiler is not allowed to 'optimise away' any access to the variable. Everywhere you place a reference to that variable (read or write), the compiler is obliged to explicitly access the variable.

In the context of your assembler ISR (or indeed any assembler), volatile is meaningless. But in the context of the main-line C code that accesses the same shared variable, volatile is important. Without it, the compiler might 'optimise away' accesses to the variable because its execution path analysis tells it the variable doesn't change. This is because the compiler can't know that the ISR can change the variable too. The ISR is considered to be a different 'thread'. Declaring a variable volatile is a way around this.

So, it wouldn't be 'less of an issue', rather volatile is a requirement when sharing a variable between an ISR and main-line code, but only if one or both of those accesses are done in C.

Search the forums for 'volatile', there are several recent threads pertaining to it. And have a look at @clawson's signature.

Quote:
When I calculated the 'worst case', I was surprised to find the degree of the error, so I think it's worth exploring options.
Another strategy that might bear some scrutiny is 'nested' interrupts.

Normally when an interrupt occurs, interrupts are globally disabled while the interrupt is being serviced. The RETI at the end of the ISR re-enables them. This is good and right, but it means that interrupts which occur while the mcu is already servicing another get deferred. This, as mentioned, may be part of your trouble.

In some circumstance the programmer may decide to deliberately re-enable interrupts in an ISR, either immediately as the first instruction of the ISR or anywhere else before the terminating RETI.

This confers the advantage that any pending interrupts are serviced immediately, instead of after the whole of the current ISR is complete and has returned with RETI. In essence you can limit the additional latency suffered by the pending interrupt to about 7 cycles (the 6 cycle latency of the current interrupt, plus 1 cycle for the SEI which enables global interrupts).

The risk is that if your application receives more interrupts than it can process with available resources (CPU cycles, stack space), your application will fail, probably in a spectacular fashion.

Indeed, the notion of nested interrupts is a controversial one, and I'll probably attract some criticism for suggesting it. These concerns are non unwarranted. A thorough analysis of your applications interrupt behaviour, and cpu, stack, and other resource utilisation is important before you can commit to a nested interrupt approach.

In your case, the timer interrupt is the possible candidate for an early re-enabling of interrupts because it is the INT0 interrupt (and your RPM calculations) that can suffer the most from additional latency.

Quote:
I know it can be easy to get caught-up in the esoteric and loose sight of the real task. :wink:
You and me both ;)

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You cannot reserve other registers besides this set.
That's a shame (although not a huge one). There are some instructions that can only operate on certain registers. For example, ADIW and SUBI work only with register pairs R24/R25, R26/R27, R28/R29, and R30/R31. While their byte-wide brothers SUBI and SBCI can perform the same operations on all registers, and at the same speed (ADIW and SUBI each take 2 cycles, and perform the same function as a pair of 1-cycle SUBI/SBCI instructions), they take an extra word of flash to do it. Not a big deal, unless you're trying to squeeze your ISR into the interrupt vector table.

Also, you're limitted to 4 registers in total for your register variables. That should be sufficient for your needs.

By the way, if you're going to venture into the deep dark wonderful world of assembler, keep one of these on your belt.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
I think you made this comment before your new-found understanding of the limitations of arithmetic operations and their need for general purpose registers.
Yes, you are correct.
joeymorin wrote:
In the context of your assembler ISR (or indeed any assembler), volatile is meaningless. But in the context of the main-line C code that accesses the same shared variable, volatile is important.
The notion of volatility is new for me, and obviously is still unclear. Thank you for pointing that out. I seem to get it confused with a variable being global. I will need to do more studying. :oops:
joeymorin wrote:
Indeed, the notion of nested interrupts is a controversial one
I thank you for introducing me to this concept, but for now I think it is a little more than I want to chew at this time. :shock: :wink: I suspect streamlining the ISRs will be sufficient to get acceptable performance.
joeymorin wrote:
ADIW and SUBI work only with register pairs R24/R25, R26/R27, R28/R29, and R30/R31.
So the ISR will need to move the bytes before they can be incremented.... Doesn't that eliminate the advantage of reserving the registers for tachCount?
joeymorin wrote:
By the way, if you're going to venture into the deep dark wonderful world of assembler
Thanks JJ, I was really just planning on peering out into the valley... or maybe just a short visit... if that is possible.... :shock:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
The notion of volatility is new for me, and obviously is still unclear. Thank you for pointing that out. I seem to get it confused with a variable being global. I will need to do more studying. :oops:
Here's a good place to start.
Quote:
So the ISR will need to move the bytes before they can be incremented.... Doesn't that eliminate the advantage of reserving the registers for tachCount?
This:
SUBI R24, 0x12 ; 1 cycle, 1 word
SBCI R25, 0x00 ; 1 cycle, 1 word

... is equivalent to:

SBIW R24, 0x0012 ; 2 cycles, 1 word

The value 0x0012 is subtracted from the register pair R24/R25. The former takes 2 cycles, and 2 words of flash. The latter also takes 2 cycles, but only takes 1 word of flash, but is restricted to register pairs from R24 onwards, whereas the former can be applied to any register from R16 through R31.

So you won't see a speed penalty due to Imagecrafts R20-R23 limitation.

In any case, the compiler will (probably) choose the optimal instructions based on the registers in question.

JJ

[EDIT: corrections w.r.t limitations of SBCI/SUBI/SBIW]

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Nov 15, 2013 - 08:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
... is equivalent to:
SBIW R24, 0x1234 ; 2 cycles, 1 word

No, the immediate constant must be between 0 and 63. If 0x1234 was allowed the instruction wouldn't fit in one word.
Quote:
the former can be applied to any register from R0 through R31.
No, R16 to R31.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the isr is taking 2-3us, why is this an issue? Especially when measuring around 60Hz?

The signal from the engine will jitter more than that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

snigelen wrote:
No...
No...
Another hasty reply on my part. Thanks for the correction. I've edited my post for posterity.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
If the isr is taking 2-3us, why is this an issue? Especially when measuring around 60Hz?

The signal from the engine will jitter more than that.

joeymorin wrote:
Not that I want to stifle your education on assembler, registers, and ISRs, but you may want to take a step back and analyse were the problem lies, exactly.

If you're seeing problems with accuracy from your rpm calculations, you may consider other approaches beyond hand-optimising ISR code.

Indeed, there are possibly other factors at work.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
If the isr is taking 2-3us, why is this an issue?
Due to a temporary condition (a cranial/rectal inversion :shock: ), I mistakenly compared those 2-3 uSec to a single 'tachCount' period (to find the error) instead of comparing it to the 75 mSec counting window. :oops: So rather than the 1.1 % error I thought I had, the actual error is 10 rpm at any speed (one 'tachCount' during the counting window). Besides that, (now that I am relieved of the afore mentioned temporary condition), I see that speeding up the ISR would have no overall effect on that error! :oops: :shock: It would only change the particular counting window it would occur in, not the number of occurrences (plus, the error would be corrected in the very next counting window - it would not accumulate).
Kartman wrote:
Especially when measuring around 60Hz?
Well... it's actually worse... it's 13.333 Hz. :shock: :oops:
Above, I wrote:
I know it can be easy to get caught-up in the esoteric
Well... maybe I DON'T know! :shock:
joeymorin wrote:
Indeed, there are possibly other factors at work.
:oops: Yeah... like the afore mentioned condition.... :oops:

Thank you Kartman for waking me up! This whole ISR discussion may have been unnecessary, but it is more input toward my overall AVR education. I appreciate all the comments and also thanks to JJ. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After finishing the tachometer hardware, I had this nagging dissatisfaction with the brightness of the 7 segment displays. I looked for brighter ones but all I found were rated in ucd and the discrete LEDs were rated in mcd. No wonder I was not satisfied with the brightness. :shock: It kept bothering me and I kept trying to convince myself they would be fine. Well, I finally decided to do something about it. So I disassembled the gauge and removed the 7 Segment displays and replaced them with a small PC board with bright LEDs. Here is what it looked like before:

And after... (the PC board at the bottom is what it looked like before the LEDs):

So then I needed to make diffusers like I made for the bar graph of the gauge. Here I'm cutting a pocket (with my CNC) in translucent white acrylic and leaving the horizontal segments of 7 segment numbers:

Below, the vertical segments being cut out. Notice the two pins that are cut on each segment that will be used to locate them properly:

This is what the vertical segments look like ready to place in the pocket with the horizontal segments:

You can see here how the vertical segments fit into the rest of the assembly:

Aluminized mylar is inserted between segments to keep light from bleeding through the small gaps between segments:

Epoxy is poured into the pocket and allowed to cure. Then the diffuser is faced off on top and bottom, and then the perimeter is cut to size.

The new diffuser is then installed into the window of the existing diffuser.

Since I was making new digits, I figured I might as well make them larger. So that means I need to make a new engraved face. Here you see the new one with the old one (the new one is on the left):

This is the tachometer put back together:

The brightness of the old vs new 7 segment display is like night and day! It may even be bright enough for sunlight reading. It saturates the sensor in the camera when taking the above photo.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
...an epic tale...

Clearly I should just go back to digging holes for a living... :|

Holy smokes. Nice work! And thanks for documenting it so well.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Nice work!
Thanks JJ. Oh, and don't sell yourself short, you have contributed greatly to this gauge! My strength is mechanical hardware which can show up well in photos. Your strength is (I'm assuming) software, which isn't so easy to show in a photo. :wink:

joeymorin wrote:
And thanks for documenting it so well.
I hope by my documenting this, it gives others ideas and incentive so they create something they can be proud of.

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All projects have build or buy decisions. I use a ForgeEuropa .3" white seven segment led that hurts my eyes. I cant remember what they cost, maybe a couple bux per digit. But I've never seen anyone make their own displays. I even asked the ForgeEuropa sales dude if they would make a 5x7 dot-matrix white led 5.6mm hi. A dumb display I could refresh with a tiny. They weren't interested. Not enough predicted volume. If you do that, you can have alphanumeric scrolling info on the display. I have most of it written.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
I use a ForgeEuropa .3" white seven segment led that hurts my eyes.
Thanks Bob. I just did a quick search and what I found quickly indicated they are sill only 1/10 the intensity of the LEDs I have. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
I just did a quick search and what I found quickly indicated they are sill only 1/10 the intensity of the LEDs I have. :wink:
Looking forward to seeing a sun-lit shot!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Looking forward to seeing a sun-lit shot!
Don't hold your breath... that sounds like a real difficult photo to get. :shock: (I wish cameras had the fancy digital processing that our eyes have....) :wink: Oh, and I'm in north western Washington... sunshine is not easy to find this time of year.... 8)

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been wrestling with the software PWM for the top segment of the bar graph. I'm looking for assistance in structuring the program.

To bring everyone up to speed... the bar graph has a segment for every 100 RPM. I want to PWM the top segment so if the RPM were 2450, the segment representing 2400 would be lit and the next segment would be 50% duty cycle, for example.

The bar graph uses PCA9922s (shift registers) to drive the LEDs and the 7 segment displays use a MAX7219. There are 5 PCA9922s that are loaded in parallel (using a look up table) and the 7219 uses the USI output. All chips are clocked together using SCK.

I have a routine that outputs all data, and it works great. The issue I have is that I need to output the data when a timer interrupts. Currently it is free running independent of the timer.

As of now, my program structure makes this cumbersome. I planned on making a loop, but I can't seem to figure out how to do it. Here is what I want the loop to do, but the loop is unrolled. Each time data is sent to the 9922s there is an opportunity to leave the top segment on or off. The 7219 needs all 10 bytes to complete the information to refresh all digits.

#define HI7219() PORTB |=  0x01
#define LO7219() PORTB &= ~0x01
#define HI9922() PORTA |=  0x02
#define LO9922() PORTA &= ~0x02
//	Preset MAX7219 Load & Serial Clock bits
#define INITPB() PORTB |=  0x05
//	Set PCA9922 Data bits
#define CLEARA() PORTA &= ~0xf4

// - - - - - - - - - - - - - Send Data to Display - - - - - - - - - - - - - - -

// - -  Wait for timer interrupt here

  LO7219();                       //select MAX7219 chip
  Display(SegsOn, 0x01);          //BarGraf segments : 7219 = 1st digit

// - -  Wait for timer interrupt here

  Display(SegsOn, digit[0]);      //BarGraf segments : 7219 1st digit = digit[0]
  HI7219();                       //latch data in MAX7219

// - -  Wait for timer interrupt here

  LO7219();                       //select MAX7219 chip
  Display(SegsOn, 0x02);          //BarGraf segments : 7219 = 2nd digit

// - -  Wait for timer interrupt here

  Display(SegsOn, digit[1]);      //BarGraf segments : 7219 2nd digit = digit[1]
  HI7219();                       //latch data in MAX7219

// - -  Wait for timer interrupt here

  LO7219();                       //select MAX7219 chip
  Display(SegsOn, 0x03);          //BarGraf segments : 7219 = 3rd digit

// - -  Wait for timer interrupt here

  Display(SegsOn, digit[2]);      //BarGraf segments : 7219 3rd digit = digit[2]
  HI7219();                       //latch data in MAX7219

// - -  Wait for timer interrupt here

  LO7219();                       //select MAX7219 chip
  Display(SegsOn, 0x04);          //BarGraf segments : 7219 = 4th digit

// - -  Wait for timer interrupt here

  Display(SegsOn, digit[3]);      //BarGraf segments : 7219 4th digit = digit[3]
  HI7219();                       //latch data in MAX7219

// - -  Wait for timer interrupt here

  LO7219();                       //MAX7219 load line low
  Display(SegsOn, 0x0a);          //BarGraf segments : 7219 = Set Brightness

// - -  Wait for timer interrupt here

  Display(SegsOn, 0x0f);          //BarGraf segments : 7219 = Brightness to full
  HI7219();                       //MAX7219 load line high

//------------------------------------------------------------------------------

Any suggestions are welcome!

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Naively:

ISR () {
  static uint8_t phase;
  switch (phase) {
    case 0:
      //select MAX7219 chip
      LO7219();                       
      //BarGraf segments : 7219 = 1st digit
      Display(SegsOn, 0x01);          
      break;
    case 1:
      //BarGraf segments : 7219 1st digit = digit[0]
      Display(SegsOn, digit[0]);      
      //latch data in MAX7219
      HI7219();                       
      break;
    case 2:
      //select MAX7219 chip
      LO7219();                       
      //BarGraf segments : 7219 = 2nd digit
      Display(SegsOn, 0x02);          
      break;
    case 3:
      //BarGraf segments : 7219 2nd digit = digit[1]
      Display(SegsOn, digit[1]);      
      //latch data in MAX7219
      HI7219();                       
      break;
    case 4:
      //select MAX7219 chip
      LO7219();                       
      //BarGraf segments : 7219 = 3rd digit
      Display(SegsOn, 0x03);          
      break;
    case 5:
      //BarGraf segments : 7219 3rd digit = digit[2]
      Display(SegsOn, digit[2]);      
      //latch data in MAX7219
      HI7219();                       
      break;
    case 6:
      //select MAX7219 chip
      LO7219();                       
      //BarGraf segments : 7219 = 4th digit
      Display(SegsOn, 0x04);          
      break;
    case 7:
      //BarGraf segments : 7219 4th digit = digit[3]
      Display(SegsOn, digit[3]);      
      //latch data in MAX7219
      HI7219();                       
      break;
    case 8:
      //MAX7219 load line low
      LO7219();                       
      //BarGraf segments : 7219 = Set Brightness
      Display(SegsOn, 0x0a);          
      break;
    case 9:
      //BarGraf segments : 7219 = Brightness to full
      Display(SegsOn, 0x0f);          
      //MAX7219 load line high
      HI7219();                       
      break;
  }
  if (phase == 9) {
    phase = 0;
  }
  else {
    phase++;
  }
}

//--------------------------------------------------------

Untested.

Is Display() a function or a macro? Note that when calling a function from an ISR you run the risk of incurring a lot of overhead, with GCC at least. A look at the generated assembly will tell you how CV handles it.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks JJ. I'll be studying your code.

joeymorin wrote:
Is Display() a function or a macro?
This is Display():
//------------------------------------------------------------------------------
//                              OUTPUT TO DISPLAY
//------------------------------------------------------------------------------
void Display(unsigned char SegsOn, unsigned char dataByte)
{
unsigned char clkLO, clkHI;
  clkLO = (1<<USIWM0) |           //set to 3-wire mode
	       (1<<USITC);             //toggle SCK pin
  clkHI = (1<<USIWM0) |           //set to 3-wire mode
	       (1<<USITC)  |           //toggle SCK pin
	       (1<<USICLK);            //shift one bit of USI shift register

  LO9922();                       //PCA9922 load line low

    USIDR = dataByte;             //load USI data register with high byte

  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][7];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][6];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][5];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][4];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][3];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][2];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][1];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK
  PORTA &= 0x0b;                  //clear PCA9922 data pins
  PORTA |= Table9922[SegsOn][0];  //set PCA9922 data pins
  USICR = clkLO;                  //toggle SCK
  USICR = clkHI;                  //toggle SCK

  HI9922();                       //PCA9922 load line high
}

joeymorin wrote:
Note that when calling a function from an ISR you run the risk of incurring a lot of overhead
The ISR only sets a flag.
//******************************************************************************
//********************************* TIMER1 ISR *********************************
//******************************************************************************
#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
  tick++;                         //tick = 780 uSec
  start = 1;                      //set start flag
}

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What immediately comes to my mind is how long does display() take to execute and is there any advantage to unrolling the loop? My guess is the advantage would be minimal, however, hard numbers talk louder. Then you can estimate how long it would take to update the whole display in one go.
To do your pwm of the bar graph, you only need to update the 9922 with the segment of interest at the timer tick rate - the rest of the display can update at a much lower rate. That gives you the option of spreading the rest of the other display out over a number of timer ticks if you so desire.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
is there any advantage to unrolling the loop?
Thanks Kartman, I guess I didn't make myself clear. What I have is an unrolled loop and I want to make it into a loop. The advantage (I think) would be a more simple and succinct program.
Kartman wrote:
you only need to update the 9922 with the segment of interest at the timer tick rate
The 9922s are loaded in parallel using a look up table. Loading one will load them all. If I want to do one at a time, I have to rewrite the entire subroutine, with the end result of no advantage. The 7219 is also done in parallel with the 9922s. It only takes a few extra clock cycles (5 I think) to toggle the latch and load the USI shift register. I don't see any reason to separate everything since it works well and I get everything in basically the same time it takes for one. :wink:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
A look at the generated assembly will tell you how CV handles it.
Whoops, I misremembered... you're using Imagecraft...

Anyway,

aeroHAWK wrote:
This is Display():
Which would make the ISR a bit too fat, even if the compiler realises it can be inlined (which is why I said "Naively" :))
Quote:
The ISR only sets a flag.
Move the ISR code I posted into it's own function, and call it from main():
  CLI();
  if (start) {
    start = 0;
    SEI();
    DisplayLoop();
  }
  SEI();

DisplayLoop() consists of all the code I previously posted in the ISR, including the static variable phase. That static variable is what lets DisplayLoop() iterate over the ten passes of your 'loop'.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Whoops, I misremembered... you're using Imagecraft...
It's okay JJ, I don't hold it against you. :wink: (My memory isn't what it used to be.... :shock: )
joeymorin wrote:
Move the ISR code I posted into it's own function
joeymorin wrote:
DisplayLoop() consists of all the code I previously posted in the ISR, including the static variable phase. That static variable is what lets DisplayLoop() iterate over the ten passes of your 'loop'.
Yep, that's what I figured... THANKS JJ!

Your suggestion knocked me off my ineffective thought process and gave me a different perspective that appears to be faster and more elegant! :lol:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aeroHAWK wrote:
knocked me off my ineffective thought process and gave me a different perspective
Probably because early on you started out with a loop.

But then you later added the need to step through one 'pass' of this former loop with each run of an ISR, effectively interleaving each pass with other code. You identified the need to unroll the loop, but perhaps continued to think of it as a loop.

This perhaps made you miss the nature of the new problem that needed solving. When you stop thinking of it as a loop, a simple state machine presents itself as a good solution.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Probably because early on you started out with a loop.
Yep, I had tunnel vision. :shock:

Cris

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery (1900 - 1944)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you spread the update over 10 ticks, then how are we going to modulate the brightness of one segment? I gather this is the core issue? Or maybe i'm just a couple of steps ahead?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
If you spread the update over 10 ticks, then how are we going to modulate the brightness of one segment?
When calling the Display() subroutine:
  Display(SegsOn, digit[0]);

SegsOn is a variable that dictates the number of bar graph segments that are on. If the first six ticks SegsOn = 25 and the last four ticks SegsOn = 24 segments, the PWM of the top segment is 60% duty cycle. Each tick is 300uS. So each update takes .003 Sec.

It takes 10 ticks to update the bar graph (including top segment PWM).
It takes the same 10 ticks to update the 7219 four digits (including intensity).

I