Author Topic: Digispark + VirtualWire (Solved!)  (Read 38746 times)

Bluebie

  • Sr. Member
  • ****
  • Posts: 486
Re: Digispark + VirtualWire (Solved!)
« Reply #30 on: April 11, 2013, 05:39:17 pm »
As I understand it the VirtualWire library is quite timing sensitive. This is one of the core reasons for the creation of the Manchester library (which I've ported to the digispark with some success). If you'd like to improve the timing accuracy of your digispark you can install the unsupported bootloader upgrade by going in to the Tools menu, and choosing Burn Bootloader, then plug your digispark in, wait for programming to finish, then wait a further five seconds. After this, your bootloader will have been upgraded to 1.06, which fixes the clock speed to 16.5mhz regardless of if it was plugged in to USB when it started or powered in a different way. The 16.0, 8, and 1mhz board options know about this feature and automatically detect it, so 16.0mhz mode will adjust down from 16.5mhz at startup regardless if it was started from USB or not, and the resulting clock speed will therefore be more stable, as with current versions there can be two different 16.0mhz clock speeds depending if the chip started up naturally or with USB, one adjusting down from the precisely calibrated 16.5mhz speed and the other just using the default atmel configuration which is only specified as accurate to within 10% of 16.5mhz (rather than the <1% deviation of the USB calibrated speed).


Digistump wont replace your digisparks if the bootloader upgrade doesn't work correctly, so be careful not to bump it during the upload and unplug shields if you can.

r4z0r7o3

  • Newbie
  • *
  • Posts: 23
Re: Digispark + VirtualWire (Solved!)
« Reply #31 on: April 12, 2013, 05:28:14 pm »
As I understand it the VirtualWire library is quite timing sensitive.

Thanks Bluebie.  The calculation is based off the MCU speed symbol (don't remember name), so I'm assuming that value is fixed at compile time.  Certainly changes in the real speed at runtime would be problematic.  Especially if Tx and Rx devices are running different underlying hardware.

Bluebie

  • Sr. Member
  • ****
  • Posts: 486
Re: Digispark + VirtualWire (Solved!)
« Reply #32 on: April 13, 2013, 08:27:46 am »

Yep, the symbol (F_CPU) is fixed at compile time. One thing to look out for is a lot of arduino software does maths which assumes F_CPU will be whole millions, like 16000000 or 8000000. They'll do things like (F_CPU / 1000000UL) to get 16, then use that in timing related math, chopping off the .5 when using the regular digispark core.


If you're interested in playing with the clock speed a bit, you can speed up the digispark by incrementing OSCCAL like this:


Code: [Select]
void setup() {
  OSCCAL += 1;
}


Then the spark will run a tiny bit quicker after that line. You can add or subtract numbers as high as 32 before getting out of the atmel spec. If you need to go higher than that, do it using a loop or something so it moves in steps of 32 or less.


There's neat stuff you can do with OSCCAL. Spritemods made an chiptune generator which broadcasts an FM radio signal out of the chip itself with no extra components! I think that code should work without any modifications on a digispark, but I don't own an FM radio to test it with! If you haven't seen spritemods site before definitely check it out. It's full of amazing stuff you can do with chips identical to or very closely related to the ones used in arduinos and digisparks. <3

r4z0r7o3

  • Newbie
  • *
  • Posts: 23
Re: Digispark + VirtualWire (Solved!)
« Reply #33 on: April 13, 2013, 12:21:43 pm »

Yep, the symbol (F_CPU) is fixed at compile time. One thing to look out for is a lot of arduino software does maths which assumes F_CPU will be whole millions, like 16000000 or 8000000. They'll do things like (F_CPU / 1000000UL) to get 16, then use that in timing related math, chopping off the .5 when using the regular digispark core.

Neat, didn't know that.  VirtualWire doesn't do this, it uses *gasp* float math.  However, it's only done once at the beginning then forgotten about.  I think the overall message is, timing is both very powerful and very tricky / problem-prone at the same time :S

TheNorthForty

  • Newbie
  • *
  • Posts: 1
Re: Digispark + VirtualWire (Solved!)
« Reply #34 on: May 14, 2013, 12:42:59 pm »
Many many thanks for your work on this!


I've run into a snag with RX on the DigiSpark. I'm trying to use PWM on 0,1, and 4 to analogWrite 3 RGB values to an LED. PWM works just fine prior to adding the virtualwire library. The code below works on a 328p. On the DigiSpark, pins 0 and 1 won't PWM, and the DigiSpark hangs when I try to send pin 0 anything other than 0 or 255.


I'm fairly new to coding, so hopefully this isn't too simple of  a question.


Code: [Select]

#include <VirtualWire.h>


int redPin = 0;
int greenPin = 1;
int bluePin = 4;


void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);


  vw_set_rx_pin(5);
  vw_setup(2000); // Bits per sec


  vw_rx_start();       // Start the receiver PLL running
}


void loop()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;


  if (vw_get_message(buf, &buflen)) // Non-blocking
  {


    analogWrite(redPin, 255 - buf[0]);
    analogWrite(greenPin, 255 - buf[1]);
    analogWrite(bluePin, 255 - buf[2]);


  }
  delay(100);
}



RC Navy

  • Jr. Member
  • **
  • Posts: 54
  • When you like, even too much, it is not enough!
Re: Digispark + VirtualWire (Solved!)
« Reply #35 on: May 19, 2013, 09:46:23 am »
TheNorthForty,

<VirtualWire> uses timer0 and breaks configuration for PWM.
Today, you can try to use the new <VirtualWire> and <TinySoftPwm> libraries which will be available in the next Digispark IDE release.
For now, you can get them on the Digispark git repo: https://github.com/digistump/DigisparkArduinoIntegration/tree/master/libraries
This version of <VirtualWire> allows you to declare the Software PWM management function in VirtualWire which will call it in the timer0 ISR.
Like this, the software PWM management function is called periodically.

With <TinySoftPwm>, you can use any of the 6 pins of the Digispark for software PWM: this releases the Pin4 which can be re-assigned to DigiUSB!

Your sketch will become like below: (with Gamma correction described by Bluebie somewhere in the forum)

Code: [Select]
#include <VirtualWire.h>
#include <TinySoftPwm.h>

#define redPin     0 /* Declare also this pin in TinySoftPwm.h (in Digispark-Arduino-1.0.4/libraries/DigisparkTinySoftPwm/ directory) */
#define greenPin   1 /* Declare also this pin in TinySoftPwm.h (in Digispark-Arduino-1.0.4/libraries/DigisparkTinySoftPwm/ directory) */
#define bluePin    4 /* Declare also this pin in TinySoftPwm.h (in Digispark-Arduino-1.0.4/libraries/DigisparkTinySoftPwm/ directory) */
/* Note: I suggest to use Pin2 for bluePin: this will allow you to reuse Pin4 for DigiUSB if needed */

void setup()
{
  vw_set_rx_pin(5);
  vw_setup(2000); // Bits per sec
  vw_rx_start();  // Start the receiver PLL running
  vw_declare_timer_Ovf_funct(TinySoftPwm_process); /* Ask Virtual Wire to call periodically TinySoftPwm_process() in the timer0 ISR */

  TinySoftPwm_begin(128, 0); /* Overlap every 128 calls of TinySoftPwm_process(), initial PWM duty cycle = 0 */
}

void loop()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) // Non-blocking
  {
    TinySoftPwm_analogWrite(redPin,  GammaCorrection(255 - buf[0]));
    TinySoftPwm_analogWrite(greenPin, GammaCorrection(255 - buf[1]));
    TinySoftPwm_analogWrite(bluePin, GammaCorrection(255 - buf[2]));
  }
  delay(100);
}

uint8_t GammaCorrection(uint8_t Pwm)
{
  return((Pwm*Pwm)>>8);
}

For people interested with Hardware PWM and Software PWM (with <TinySoftPwm>) for the Digispark, I wrote a chapter on the wiki:
http://digistump.com/wiki/digispark/tricks#hardware_software_pwm

Hope this helps,

RC Navy
« Last Edit: May 19, 2013, 11:17:00 am by RC Navy »