How to access hardware registers


#1

Hi, I’m just starting to look at Zerynth after having played with C and Arduino for a while now.
One thing I like about the Arduino IDE is it allows direct access to the hardware registers. e.g. for Arduino Nano and Mega the timer registers TCCR1A, TCCR1B, TIMSK1 etc can all be directly referenced in the program. This makes it very simple to use a timer to create a PPM output stream (for control of R/C toys), as it requires only some register settings and an ISR with two lines of code in it. There is no code at all required in the main loop. Similarly the port registers DDRB etc can be manipulated. This also works for the Due, where e.g. PIOA_SODR can be referenced, although in the Arduino it has to be referanced as REG_PIOA_SODR. (I’ve never discovered where these names are defined however…). Also works with Teensy35 (e,g, ADC1_SC1A).
So, is it possible to reference registers in Zerynth? Or is it preferable to use builtin functions? I’ve only just begun exploring those (adc.read etc) so haven’t really wrapped my head around it all yet. But it seems there may be some cases to use the registers, for more fine grained control of PWM for instance, or use the ADC in free running mode.
All advice gratefully received.


#2

Hi mogplus8,

this is a very interesting question; Zerynth, in one of its main purpose, enables the Python programming for 32-bit microcontrollers easying the development of user applications and leaving the “dirty work” (low-level registers and peripherals management) to the Zerynth Virtual Machine.

Said that we recommend to use our built-in functions and defines:
 - here you can find the Timer lib (here an example);
 - here you can find the ADC lib (here an example);
 - here the onPinRise/onPinFall functions to handle the ISR (here an example);
 - here the PWM lib (here an example).

In general, Zerynth also allows the “hybrid” programming (C and Python); so you can include .c/.h files in your project following the Zerynth syntax for integrating C language in Python scripts and inside a C file you can do whatever you want from a complex function to low-level register settings.

To follow the second programming way, you have to be careful because you may enter into conflict with VM functionalities and for sure you will lose another main advantage of the Zerynth ecosystem: the Hardware Abstraction Layer that allows code reuse on all the other Zerynth Supported Devices.

Hope this can help you :slight_smile:


#3

Hi Matteo,
thanks for the quick response.
I thought the answer would be something along the lines of your response, given the greater complexity of Zerynth (as opposed to the “down and dirty” programming that can be done more easily with C on 8 bit processors) and the power of the language and the underlying architecture. Using higher level functionality makes sense as the need to minimise code and maximise efficiency is not as great.
It would be nice to be able to get at the registers though. Obviously they are used by the built in libraries otherwise the timers, ADC etc. could not be made to work. For me personally, portability is not a problem. I’m just a hobbyist who enjoys the challenge of programming, and I have a couple of small projects to play with, one on a Due, and one on a Teensy35 (you are going to support Teensy aren’t you?..) I’m not planning on sharing my code with anybody but happy to do so if anybody would like it, but that’s not my main focus. You won’t find my account on GitHub. But I’ll save digging around in the registers for another time when I’m a lot more familiar with the framework.
Thanks,
Ian


#4

Well, here I go again.

I want to generate a PPM signal on an output pin. A PPM signal is a string of pulses on an output pin, where the low pulse width is always 300 microseconds (us), and the high pulse width will be somewhere between 700us and 1700us depending on a value supplied. For radio control applications this would normally be read (analog read) from the stick positions of the transmitter. After all channels have been sent, i.e. a string of pulses (typically eight) have been sent, a much longer “sync” pulse is transmitted that tells the receiver the next pulse will be channel 1. The sync pulse is 22,500 minus the sum of the “data” pulses, so each “frame” is the same length, 22,500us. Not all transmitters use a 22,500us frame size, but most do. This gives a frame rate of about 44 frames per second.

My question is, how do I set that up in Zerynth? It seems logical to use the hardware timer (I’m using an Arduino Due for this. Yes, I know, wrecking ball to crack a peanut. But there’s lots more functionality to go yet) because this is exactly the sort of thing it was designed to do. Count off a number of microseconds then flip a pin, but there is only one function implemented for the hardware timer, sleep_micros, which can’t be used for this requirement. I looked at the PWM function and it seems to do some of what I want. I could do something like pwm.write(signalPin, value, value + 300, MICROS, npulses=1) where value comes from an analogRead(An). The documentation for vhalPwmStart(which is presumably what pwm.write() and analogWrite() call) says that it blocks the current thread until the requested number of square waves requested is generated, than returns. So could I put it in a high priority thread in an endless loop on its own with a few lines of code to read the next value from a list (tuple? array?) Then in another thread cycle around my analog inputs (sticks, knobs, sliders), and do all the other calculations required to build the tuple(?) of channel values to be transmitted, then share that with the PPM thread somehow?

Is there a better way?..

Thanks, Ian



#5

Hi Ian,

your idea is a good way to implement what you need.
If you need “manually” signal construction, adafruit neopixel library can be a good starting point.

In this library, we need a signal period of 1,25 us and different timing to send a ‘1’ or ‘0’ logic level; obviously, to reach a microsecond precision, signals have been built in C language using some of low-level VM function to set and clear the needed pin, but following this code and setting the right timing you can easily built you PPM signal. (under “zerynth2/dist/r2.0.10/libs/official/adafruit/neopixel/csrc/ledstrips/ledstrips.c” you can find the C language code and under “zerynth2/dist/r2.0.10/libs/official/adafruit/neopixel/ledstrips.py” the related Python implementation)

Let me know if this can help you, and feel free to write me if you need any further help :slight_smile:


#6

Thanks for that Matteo. I’ve had a look at the code and didn’t understand most of it, so clearly I have some study to do.
:wink: Ian