This repository contains information about generating squarewave signals using arduino hardware via bit-banging using interrupts.
The original motivation was to simulate a signal generated by a rotational-speed sensor.
The following diagram shows the signal sequence generated by one rotation:
+---+ +---+ +---+ +-- -+ +---+ +---+
| | | | | | | ... | | | | |
+ +---+ +---+ +---+ +---+ +---+ +---+---+---+---+---
1 2 3 4 61 62 63 64
As you can see the signal value high is triggered 62 times followed by a short pause.
The initial requirement was that the signal frequency should be as high as to simulate 7000 rotations measured by the rotational-speed sensor. We denote this frequency as wheel frequency. Since one rotation generates a signal containing 64 sections the signal frequency is 64 times higher.
The microcontroller ATmega328P contained on the Arduino Nano V3 has three hardware timers capable to generate PWM signals. But since the signal we want to generate contains a pause at the end of each rotation of the wheel we have to modify the signal PWM signal in some way. We are using an interrupt to change the signal values 0/1 which is triggered by a hardware timer at the appropriate frequency.
Since timer 1 is a 16-bit timer which is counting at 16 Mhz (with prescaler set to 1) it takes 4096 us (4096 microseconds = (1/16 MHz)*2^16) to trigger an overflow. You can define a compare register to trigger an interrupt if the counter has reached a specific value, i.e. you can trigger at any interval between 1/16 MHz and 4096 us.
Since the calculation and setting of the output pin which is done in an interrupt service routine needs some amount of cpu cylcles the frequency of the interrupts can not be close to 16 MHz.
The calculation of the signal can be done using the following pseudo code using a global volatile byte typed variable count:
+---+ +---+ +---+ +-- -+ +---+ +---+
| | | | | | | ... | | | | |
+ +---+ +---+ +---+ +---+ +---+ +---+---+---+---+---
0 1 2 3 4 5 6 120 121 122 123 124 125 126 127
volatile byte count = 0
set counter of timer 1 to 0
if (count % 2 == 0 and count < 124):
set output to 1
else
set output to 0
count++
count = count % 128
Now the question remains what is the maximum wheel frequency we can achieve, i.e. how much time or cpu cycles does the interrupt service routine use.
If you have a two signal oscilloscope with an appropriate bandwidth, you can measure this by setting a different output pin to 1 at the beginning and 0 at the end of the routine.
We measured that > 160 cpu cycles are necessary. Defining 320 as the minimum for the compare register yields wheel frequencies > 20000 rpm.
- FastWrite
If you are using a nano clone with CH340 chip you have to install the driver (see [3]) and use "ATmega328P (Old Bootloader)" as processor within the arduino IDE.
README.md - readme (english)
LIESMICH.md - readme (german)
v1_1000_rpm - yields ~ 1000 rpm
v1_maximum - proof of concept that 20000 rpm can be reached
v1_measurement - was used to determine minimum value for compare interrupt
Details about timers and interrupts are available at [1]. The used arduino clone "Nano V3.0 CH340" is available at [2]. Install instructions regarding CH320 USB2Serial chip driver are available at [3].
[1] https://www.heise.de/developer/artikel/Timer-Counter-und-Interrupts-3273309.html (german)
[2] https://www.az-delivery.de/products/nano-v3-0-pro (german)
[3] https://www.makershop.de/ch340-341-usb-installieren/ (german)