ISR 'bug' in stirplate design.

Status
Not open for further replies.
Im still confused as to what it is you are trying to do. As someone who works and plays in the electric propulsion industry I find your need for perfectly synced outputs a little puzzling considering your only running a small motor. I'm also not sure that your static sin wave will work out so well. There is a lot of math involved in properly running an AC motor based on the load. Over speeding or stalling/regening can cause voltage spikes that can damage circuits unexpectedly.
 
Happy New Year !!! Is this picture worth 1,00 words? 70 lines of code? Worked well enough in this pic . . .

StirPwmLA.jpg

Read up on SINE enough to kludge a 2344 element array in 93ms in Setup (CSV printed to USB but what's 93ms). Went with 0-1023 values since that matched 46875 Hz freq.

Used elapsedMicros in loop() to make a 'clock' to tell me when to do the next analog write. [ignore the isr_ names I started with]

First REAL use running wires to PWM on Pin5 & LED#13 to My-Teensy-Logic-Analyzer on a second Teensy - showed me what I needed to see, much to learn. { though the time units seemed confused at times }

Had to Abandon the beloved TYQT because it steals USB port from Logic Analyzer :-( , Had to power down analyzer Teensy to upload StirPWM code as it was #2 [DOH!].

Wrote out the indexed PWM value in sync with the freq every (1000000*1/46875) microseconds == 21.33 us. PWM'd sin() to array's end then reversed and repeated, at full speed (captured in image).

Oh yeah - all the updates were 2ms apart - then I remembered reading somewhere: analogWriteFrequency(5, 46875);

Code Snippet with Debug prints mostly gone- full INO below:
Code:
#define SSVALS_SIZE 2344  // # bins for 46875 / 20
uint16_t ssvals[SSVALS_SIZE];
elapsedMicros eus;

float MicrosVal = 1.0 / 46875.0;
uint32_t eusPWMVal = 1000000 * MicrosVal;

#define qBlink() (digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ))  // Pin13 on T3.x & LC
void setup() {
  eus = 0;
  Serial.begin(38400);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
  while (!Serial && (millis() <= 2000))
    qBlink();
  MakeTable();
  analogWriteResolution(10);  // analogWrite value 0 to 1023  [B]// <edit> this line was missing[/B]
  analogWriteFrequency(5, 46875);   // analogWrite value 0 to 1023 at 46875 Hz
  eus = 0;
}

uint16_t isr_ii = 0;
uint16_t jj = 0;
uint8_t isr_state = 0;

void loop() {
  if ( eus >= eusPWMVal )
  {
    eus = 0;
    analogWrite(5, ssvals[isr_ii]);
    qBlink();
    if ( !isr_state ) {
      isr_ii++;
      if ( jj == isr_ii ) Serial.println( ssvals[jj]); // print one value in turn every rising cycle
      if ( isr_ii >= SSVALS_SIZE ) {
        isr_ii = SSVALS_SIZE - 1;
        isr_state = 1;  //        Serial.println( " STATE 1 ");
        if ( ++jj >= SSVALS_SIZE ) jj = 0;  // Prepare for next value print next cycle
      }
    }
    else {
      if ( 0 == isr_ii ) {
        isr_state = 0;  //        Serial.println( " STATE 0 ");
      }
      else
        isr_ii--;
    }
  }
}


void MakeTable(void) {
  // Create SINE table 0-1023 in SSVALS_SIZE bins
  float rr = 0;
  float ss = 0;
  uint16_t ssval;
  uint16_t ii = 0;
  eus = 0;
  float rrinc = 1.570796326794 / (SSVALS_SIZE - 1);
  while ( ii < SSVALS_SIZE ) {
    ss = sin(rr);
    rr += rrinc;
    qBlink();
    ssval = 1023 * ss;
    ssvals[ii] = ssval;
    ii++;
  }
}

View attachment StirplateSine_jan01a.ino
 
Last edited:
I do realize my code is very messy and early, alot of comented out stuff. I've rewriten in and modified it countless times just trying to get the sync function to work with my isr. Thanks for looking Paul, and I don't expect anybody to rewrite my code. It just seemed silly to me to count millis, or set up an interval timer when the flex timer was timing exactly what i wanted anyways, 1 pwm cycle.
since the otherday i only modified the prescaler from 111 to 000 where it was supposed to be, it was modified before this for debuging purposes.
the logic pics i posted were with ps 000
I'm looking at the code posted from message #7. If you've changed it since yesterday... well, you didn't post anything else, so this is what I've got.

Inside ftm0_isr(), you're checking and clearing the interrupt flag on FTM1. A simple mistake, but if you don't clear the FTM0 flag, it'll keep interrupting at maximum possible rate. Fix this first!
Thats it Paul! Now I'm embarassed it was something so simple. I copied that code, and forgot to change those 1s to 0s. Now my code triggers at the end of a pwm cycle like it was meant to. Obviousely thats why it was triggering every 2.05 millis... cause i was checking the wrong module.

It also looks like you're trying to use both COMBINE and CPWMS. That combination isn't one of the documented features in table 36-67 on page 783. Who knows what it will do?! It's definitely not a legal/documented setting.

And really, what sense does center aligned PWM make if you're combining 2 channel comparators to control both the rising and falling waveform edges? Center aligned means a single comparator triggers both rising and falling edges, aligned to the center of a double-length period. Combine mode means you control the absolute position of both edges within the waveform period. Conceptually, they're mutually exclusive. You have to pick one. Combine mode gives you complete control of the both waveforms... but then you have more work to do to control them. If they're always going to both be centered within the PWM period, then center aligned will be simpler.

I don't see where i have set the cpwm bit anywhere. There is some commented out CPWM giberish though. I have the TOIE bit set though which is right next to it in that rigister. this just enables the interupt to trigger after the timer hits the mod value, or after each pulse. I chose to use combine over cpwm because it seems to have more options and only an extra line to set the both start and end channels. This allows me to setup different schemes which alternate from one set of coils to the other which would allow me to run twice the amps on my motorcontroller because the power is more evenly consumed. still in early stages.
There may be other issues. This code is longer and more complex than I really want to put much time into fixing. Maybe you could try a simpler proof-of-concept which just controls 1 pin in a simple and easy-to-observe way (not a big lookup table... something simple like alternating between a few fixed settings).

Hopefully this quick look at least helps you get onto the right path?

Thanks for the help, but I'm on track now, i'll post some more elegant code once its polished if anyone wants to see it. I know your a busy man Paul, looking forward to the next teensy release (k66)
Screenshot from 2016-01-01 16:30:01.jpg
Now the update is triggering at the same rate as the pwm... as you can see.
 
dont go to too much trouble ... Ill test run it for sure though. you just might have to wait.

sass: glad you made good progress - as you can see I got what looks to be good results using the concept I had (though my image was better on my screen that I uploaded). And in the process I learned what the heck PWM really looks like and - something I may have forgotten about rad's and the sine func - and how to use a Teensy based Logic Analyzer so I'm glad I chimed in - it was a learning lesson on multiple fronts for me and no trouble at all - maybe one hour of it was emulating your problem as I under stood it.

I do look forward to your giving my sketch a run past your Logic Analyzer and showing me a pic of it using the code above.

View attachment 5966

I'm sure it has issues - but from what I saw the core function was there at 49kHz. What device did you get for 15 bucks? That Teensy based unit uses a good public front end - so it was FREE and probably has great promise.
 
Last edited:
My code runs the array fine - but some error in restarting the loop - but it repeats eventually. I did a GEAR/jump of 5 here to the display shows the PWM width growth faster:StirPwmLA2.jpg
 
Im still confused as to what it is you are trying to do. As someone who works and plays in the electric propulsion industry I find your need for perfectly synced outputs a little puzzling considering your only running a small motor. I'm also not sure that your static sin wave will work out so well. There is a lot of math involved in properly running an AC motor based on the load. Over speeding or stalling/regening can cause voltage spikes that can damage circuits unexpectedly.

Its not a motor per say i'm running more like 4 electromagnets wired to 2 separate circiuits(sine circuit, and cosine circuit) going through an hbridge meant for a small motor Im driving these two circuits with 2 coils each in sine paterns so that the magnetic bar inside the cup on top is rotating despite there are no moving parts in my design.

Im also not using AC its using 12 volt dc runing through an hbridge so i can reverse polarity for the set of 2 coils on every half rotation

https://www.youtube.com/watch?v=HWoA9jqDp2M
This is the best homebrew design i've seen on arduino, and have yet to see a design on teensy. Mine is the first as far as i know, and it seems the ftm module is better suited to this type of thing than the timing they r using in arduino. All that aside this guy is using bigger coils than me and i think thats the biggest reason he is getting better performance(he claims 1500 rpms stable, and i havent been able to maintain anything higher than 600 with the interval timer code i was using before i decided to rewrite it with an isr and timer overflow)

biggest problem seems to be if the pulses are not consistent then the contact gets lost and the magnet falls off and just jiggles in the same spot because it has no momentum left from the swirl in the water, and then its fighting inertia.

wow didnt think i would get so much interest... its almost a bit overwhelming. this design has been rolling around in my imaginary lab inside my head for a while before i had all the parts shipped. if someone else wants to design another one of these i would recomend bigger coils than what im using.
 
Defragster,
That software front end for your logic looks like it might be nicer than the sigrok/pulseView that im using. are you running linux or windows? have you tried pulse view? does being based on java make your software slower/more resourse intensive? Bought my usb logic from dx.com Its only digital:( but gets the job done, and technicaly using teensy while better im sure(teensy can be analog scope) its not free if you need to tie up a second teensy with it. Glad to see you got you teensy doing your bidding as a scope. Did you use the project i saw on github?

ps. logic i have only goes upto 24Mhz with 8 digital ports, so its pretty kiddy but alot better than nothing.
 
When I saw I forgot the analogWriteFrequency() I corrected that by replacing the analogWriteResolution() and BOTH are required. My PWM was going '1' and I thought I had a loop issue, I learned that setting one does not inherently set the other! Posted code needs this edit to use the 1024 values I calculated. I wasn't trusting the Analyzer and I should have.

PWM calls needed in setup()
Code:
  analogWriteResolution(10);  // analogWrite value 0 to 1023
  analogWriteFrequency(5, 46875);   // analogWrite value 0 to 1023 at 46875 Hz

I'm on Windows 10. I have spare Teensy's so no cost putting another to work ;) Yes this My-Teensy-Logic-Analyzer came from GitHub through that Forum link. It only gets to use 58K of RAM from Teensy, and won't hit 24MHz on 8 channels until next week. The DISPLAY software I got is the posted public LogicSniffer he pointed to and both parts downloaded and installed cleanly following his directions. You can try it with internal test mode to see how it works. Startup is not the fastest and initial dialogs on this old 8GB i5 - but I have Arduino open and that both using Java and not rebooted in days - and caused a few JAVA faults. But once running it samples and displays in under 2 seconds - it reported 1.45 seconds for 118ms sample period at 500kHz. I have not explored much as this was all I needed to learn so far. Also the first I've ever used so nothing to compare to.

I switched to using IntervalTimer myTimer; and my code looks the same and same code works as the elapsedMicros code in loop(). If there was an interrupt when the PWM resets - you could run that to flag when the code is safe to put out the new value and not miss from the skew.

I learned quite a bit and expanded my toolset doing this. The sine pre-calc to a custom sized array in setup is handy to get the multiple you want in the array and 95ms isn't too long to wait for it.
 
Status
Not open for further replies.
Back
Top