POV math

Hi

I am finally ready to start my first POV project but just wanted to cconfirm the basic math to see if all my components fit the bill. I would like to try a rotating cylindrical shaped device as opposed to a sphere.

  1. Atmega328 at 16MHz
  2. Motor rotation speed, lets say 1800 rpm which gives 30 turns per second or 30Hz.
  3. Further lets say the resolution must be 60 points on the circumference of the cylinder which makes it 180Hz.
  4. I would then add say 64 LEDS along the length of the cylinder driven by 8 x 595 shift registers or similar.

I have seen that the SPI library can be used which apparently gives a byte output at 3uS (source
http://arduino.cc/forum/index.php/topic,59369.0.html) I assume SPI here is running at 4MHz since the clock divider was not set in the author's code.

Since I have 8 registers that is a total of 24uS to refresh all registers which translates to 1/ 0.0024 = 416Hz. This is more than double the 180Hz requirement calculated above at point 2 and thus workable.
Data would have to be read from somewhere and passed to the SPI library as well as a method of determining precise rotational speed which will add extra overhead but I can set the SPI library to 8MHz also ..

Is all this correct as a basis for my rotation speed, resolution calculations?

Also if anyone has any information they wish to share on optimum speeds, brightness for LED's etc for POVs please post that as well?

Much obliged! :slight_smile:

  1. Motor rotation speed, lets say 1800 rpm which gives 30 turns per second or 30Hz.
  2. Further lets say the resolution must be 60 points on the circumference of the cylinder which makes it 180Hz.

Can you explain the 30 * 60 = 180 bit?

Sure, if you think of a single LED moving around a set circular path at 30 revolutions per second I would like to be able to switch that LED off or on at 60 set intervals along that path per rotation. That got me to 180Hz .. then again math has never been a strong point of mine .. :~

Mm .. now that you mention it 30 x 60 is closer to 1800 isn't it .. :blush:

That got me to 180Hz

This isn't "math", this is arithmetic.
Your PC probably has a calculator - they're good at arithmetic.

Any other obvious mistakes .. ?

Whoops .. (or whatever is grammatically correct) .. found another mistake.

uS from the quoted post is microseconds but I treated it as miliseconds.

Revised arithmetic:

  1. Atmega328 at 16MHz
  2. Motor rotation speed, lets say 1800 rpm which gives 30 turns per second or 30Hz.
  3. Further lets say the resolution must be 60 points on the circumference of the cylinder which makes it 1800Hz. (thanks to PaulS)
  4. I would then add 64 LEDS along the length of the cylinder driven by 8 x 595 shift registers or similar.
  5. A single shift register refreshes at 3uS on SPI (4Mhz?) as per quote in first post which is 0.000003 seconds which totals 0.000024 seconds or 41666 Hz (1 divided by 0.000024) for all 8 registers

This still seems well within reach or am I going from bad to worse?

Seems your arithmetic problem solved. You got 100% marks now.. Now come to POV maths..Lets learn mathematics :grin:

So to calculate required refresh rate I suspect one can use the following:
Required Refresh Rate = (Motor Rpm / 60) * Horisontal 'Resolution'

I may mention that Grumpy Mike recommends 32Hz http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1278290228#3 as flicker free, which equates to 1920 rpm.

So with a 64 dot horisontal resolution and with 1920 rpm it works out to:
Required Refresh Rate = (1920 / 60) * 64
Required Refresh Rate = 2048 Hz or 2 KHz

Keep in mind that this only provides for 1 LED though.
How fast can Arduino update 64 LEDS at 16 MHz?

I did some testing with a 74HC595 and came up with the following code to test with. It uses SPI at 8Mhz and bitSet bitClear for fast latching. Anyone who knows of a faster way let me know, I'd love to 'clock' it on the o'scope.

So basically the code looks like this:

//**************************************************************//
//  Quick code to test throughput of 74HC595 
//****************************************************************
#include <SPI.h>
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 13;
////Pin connected to DS of 74HC595
int dataPin = 11;

int oPin = 10;

int latchPinPORT = latchPin - 8;


byte scopedata = 1;
byte dataa = 2;
byte datab = 4;
byte datac = 8;
byte datad = 16;
byte datae = 32;
byte dataf = 64;
byte datag = 128;



void latchOn(){
 bitSet(PORTB,latchPinPORT);
}
void latchOff(){
  bitClear(PORTB,latchPinPORT);
}

void setup() {
 
 pinMode(latchPin, OUTPUT);
 pinMode(clockPin, OUTPUT);
 pinMode(dataPin, OUTPUT);
 pinMode(oPin, OUTPUT);
  
 SPI.setClockDivider(SPI_CLOCK_DIV2);
 SPI.begin ();

}


void loop() {
  
 
  latchOff();
  SPI.transfer (scopedata);
  latchOn();

  latchOff();
  SPI.transfer (dataa);
  latchOn();
  
  latchOff();
  SPI.transfer (datab);
  latchOn();
  
  latchOff();
  SPI.transfer (datac);
  latchOn();
    
  latchOff();
  SPI.transfer (datad);
  latchOn();
    
  latchOff();
  SPI.transfer (datae);
  latchOn();
    
  latchOff();
  SPI.transfer (dataf);
  latchOn();
    
  latchOff();
  SPI.transfer (datag);
  latchOn();
}

I then attached old trusty to the ouput pin 0 of the 595 and it came up with this:

So at max myArduino can refresh 64 LEDs at 56KHz vs a required 2KHz.
Note that this was tested on a breadboard with one 595...

Next I'll try loading 512 bytes from memory into an array and clock that.
In case you're wondering .. 512 bytes = 4096 bits which is the amount of 'pixels' my theoretical POV display has (64 horizontal * 64 vertical resolution)

Again, all inputs welcome .. :slight_smile:

EDIT .. Spelling

30rev/s is a bit too fast to me. Mine spins at 4.5rev/s max, well because the motor can't spin any faster. But I'd stay within 10rev/s. I'd need a much wider magnet to trigger it if I spin it too fast.

Have you thought about what to use to trigger the display? You can't just expect your motor to spin at a constant rate. Once you realize that, you will hope to spin slower so your trigger sensor can pick up the magnet or IR that triggers the display. Spinning too fast results in missed triggers.

So what trigger mechanism?

Note too sure if I understand you correctly but 30Hz is rather slow .. sensor wise. I looked around and the first one I came across (IR interruptor type) was rated 1KHz? Omron EE-SX670OMC

Of course building a stable balanced frame is something else entirely...

JBMetal:
Note too sure if I understand you correctly but 30Hz is rather slow .. sensor wise. I looked around and the first one I came across (IR interruptor type) was rated 1KHz? Omron EE-SX670OMC

Of course building a stable balanced frame is something else entirely...

Exactly it is too fast and your sensor is too slow. I imagine you make a tab to trigger the interrupter on the rotation stage, how large will the tab be? Maybe 10 degree of angle so it is not too big. Then the tab is only under the interrupter for 1/36 of the full period so 1/1080 second, which makes your sensor too slow. I am asking because I had to switch to larger magnet for my setup due to my magnetic sensor limitation. BTW 10 degree is pretty wide so you do th math for me.

JBMetal:

void latchOn(){

bitSet(PORTB,latchPinPORT);
}
void latchOff(){
 bitClear(PORTB,latchPinPORT);
}

Just wanted to offer up, this combination may actually slow things down. IIRC, this gets compiled by default with -Os, which optimizes for size. That means its extremely unlikely those functions will be inlined*. I didn't check if the bitSet/bitClear functions were actually macros or not. If they too are functions, you likely added yet another function call. If performance were really critical here, you should likely call bitSet and bitClear directly in the code or create defines and use those rather than the latchOn/latchOff functions.

Obviously review of the resulting asm can verify, but its just something to consider if/when performance headroom ever becomes critical for your project.

  • Please note, inlining, in of itself, can also be detrimental to performance as well as lose out on the size equation.

@Gerg: Thanks for the heads up, you have brought something to my attention that was previously unknown to me. I'll try the defines route and post the results. :slight_smile:

@liudr: I think I understand now. You measure the time the reed switch is on which since the magnet is a known length lets you then calculate the speed. I was thinking of just catching the rising edge of the sensor on the interrupt and then measure time elapsed between two 'trigger' events of the sensor. This gives me the time taken to do a full rotation needed to calculate the current speed .. or am I missing something?

EDIT: spelling

Reed switches have a nasty habit of bouncing, or not closing at all.
Most POVs that I've encountered use Hall effect sensors.

Hall effect it must be then..

@Gerg: Thanks for that, I added the following and replaced the old latch functions.

#define L_PINDEF 0  // digital latch pin #8 (portb and 8-8=0)
#define LATCH_ON() PORTB |= _BV(L_PINDEF)
#define LATCH_OFF() PORTB &= ~_BV(L_PINDEF)

The output increased to 62KHz:

Wow. 8Khz gain. Pretty impressive for such a small change.

For those of you who don't know, as I previously hinted at, inlining can (not always) also hurt performance in larger application. I don't know enough about the CPU architecture of the AVR's to know if that's a noteworthy concern. Usually its cache thrashing which ultimately hurts performance from inlining. Just keep in mind, inlining via the macro trick can make your code larger. This is why, when compiling with -Os, the compiler is extremely picky about what it inlines. Which is to say, using -Os is the antithesis of inlining for speed optimization.

Usually its cache

That's unlikely to be of concern to an AVR :stuck_out_tongue_closed_eyes:

I used Hall Effect digital switch in my setup. I had smaller magnets before and my switch starts to skip around 4.5 rev/s due to the size of the magnet (not its field strength). I then replaced the smaller magnet with a larger one and solved the problem. If you run an interrupter on stage and a stationary block, you will see the same effect until you make your block large enough in size to allow at least 1ms blocking time to trigger the interrupter. That will translate to (0.03rev/ms)(1ms)=0.03 rev or 0.03360=11Deg or angle of coverage. Just make sure that happens ie you don't use a tiny slip of paper as a blocker. The paper won't spend 1ms blocking the beam.

Gotcha liudr, thanks for the heads up :slight_smile:

I found another 8KHz by adding a while (1) loop inside the void Loop.

Apparently there is a slight delay before void Loop restarts for a fuller explanation see:
http://arduino.cc/forum/index.php/topic,65014.0.html

Herewith the latest results, at 68KHz