|The Pico In MicroPython: Direct To The Hardware|
|Written by Harry Fairhead & Mike James|
|Monday, 13 December 2021|
Page 1 of 2
Just occasionally you need to work directly with the hardware and MicroPython has the commands to let you do this fairly easily but you need to know more about the hardware than usual. This is an extract from our latest book all about the Raspberry Pi Pico in MicroPython.
Programming the Raspberry Pi Pico In MicroPython
By Harry Fairhead & Mike James
Buy from Amazon.
MicroPython provides classes and methods to let you access most of the major hardware features of the Pico. They are very simple wrappers around the basic mechanism of working with the hardware – memory-mapped registers. Unfortunately at the time of writing there are many hardware features which are simply not exposed via MicroPython. In most cases it is possible to extend what you access using lower-level interactions with the hardware – still staying in MicroPython, but writing and reading the low-level register based hardware.
The obvious reason for knowing how to use memory-mapped registers is that if MicroPython doesn’t provide a function that does what you want, create it! Perhaps a better reason is just to know how things work. In this chapter we take a look at how the Pico presents its hardware for you to use and how to access it via basic software.
Some processors have special ways of connecting devices, but the Pico’s processor uses the more common memory-mapping approach. In this, each external device is represented by a set of memory locations or “registers” that control it. Each bit in the register controls some aspect of the way the device behaves. Groups of bits also can be interpreted as short integers which set operating values or modes.
How do you access a register? MicroPython provides a number of ways of doing this but the simplest is to make use of the mem functions in the machine module:
machine.mem32[address] Returns or sets a 32-bit value at the address
machine.mem16[address] Returns or sets a 16-bit value at the address
machine.mem8[address] Returns or sets an 8-bit value at the address
The only difficult part is in working out the address you need to use and the value that sets or resets the bits you need to modify.
For example, if you look in the documentation you will find that the GPIO registers start at address 0x40014000. The registers are defined by their offset from this starting address. So for example, the table of GPIO registers is:
You can see that there are two registers for each GPIO line from GP0 to GP29, one control register and one status register.
Each register has the same format for each GPIO line. For example, the status register is:
You can see that many of the 32 bits in the register are not used, but bit 9 is OUTTOPAD which is the final state of the GPIO line after register overrides have been applied. You can read its current value using:
from machine import mem32 addrGP0Status= 0x40014000 value=mem32[addrGP0Status] print(bin(value))
This prints the current status of GP0 in binary. If you want to find the status of GPn you need to use address 0x40014000+2n. Usually addresses are specified as a base address, i.e. where things start, and an offset that has to be added to the base to get the address of a specific device.
This is the general way you work with peripheral devices such as the PWM units or I2C hardware, but the GPIO is special in that it has another set of registers that control it.
|Last Updated ( Monday, 13 December 2021 )|