The Pico/W In C: Direct To Hardware
Written by Harry Fairhead   
Tuesday, 21 February 2023
Article Index
The Pico/W In C: Direct To Hardware
Single-Cycle IO Block
Example I - Events
Slew rate

Sometimes you just have to go beyond the SDK and work with the hardware - it's not so difficult. This is an extract from the latest book in the I Programmer Library, all about the Pico/W in C.

Programming the Raspberry Pi Pico In C

By Harry Fairhead

picoC2E360

Buy from Amazon.

Contents

  • Preface
  • Chapter 1 The Raspberry Pi Pico – Before We Begin
  • Chapter 2 Getting Started
  • Chapter 3 Getting Started With The GPIO
  • Chapter 4 Simple Output
  • Chapter 5 Some Electronics
  • Chapter 6 Simple Input
        Extract:   GPIO Input ***NEW!
  • Chapter 7 Advanced Input – Events and Interrupts
  • Chapter 8 Pulse Width Modulation
        Extract: Basic PWM
  • Chapter 9 Controlling Motors And Servos
  • Chapter 10 Getting Started With The SPI Bus
  • Chapter 11 A-To-D and The SPI Bus
  • Chapter 12 Using The I2C Bus
  • Chapter 13 Using The PIO
        Extract: A 1-Wire PIO Program  
  • Chapter 14 The DHT22 Sensor Implementing A Custom Protocol
  • Chapter 15 The 1‑Wire Bus And The DS1820
  • Chapter 16 The Serial Port
  • Chapter 17 Using the Pico W
       Extract: Simple Web Client
       Extract:A Better Connect
  • Chapter 18 The Pico/W In C: Direct To Hardware 

Extra: Adding WiFi To The Pico 2

<ASIN:1871962803>

<ASIN:187196279X>

Direct To The Hardware

The SDK provides functions to let you access most of the hardware features of the Pico. They are very simple wrappers around the basic mechanism of working with the hardware – memory-mapped registers. You might think that bypassing the SDK and doing the job directly via hardware access would be attractive because it is more efficient – it isn’t. The SDK is such a light wrapper over the hardware there is very little point in trying to gain the few fractions of a microsecond that direct access provides. The obvious reason for knowing how to use memory-mapped registers is for situations where the SDK doesn’t provide a function that does what you want – 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.

Registers

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? Simply by storing the values in it or by assigning its value to a variable. This is nothing new in C. The big difference is that you now have to refer not to a memory location provided by the system, but to a fixed address provided by the documentation. You still use a pointer, but one that is initialized by a constant or literal. 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 starts:

Offset

Register Name

Description

0x000

GPIO0_STATUS

GPIO status

0x004

GPIO0_CTRL

GPIO control including function select and overrides

0X008

GPIO1_STATUS

GPIO status

0x00c

GPIO1_CTRL

GPIO control including function select and overrides

… and so on down to

0x0ec

GPIO29_CTRL

GPIO control including function select and overrides

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:

Bits

Name

Description

Type

Reset

31:27

Reserved

 

-

-

26

IRQTOPROC

Interrupt to processors, after override applied

RO

0x0

25

Reserved

-

-

24

IRQFROMPAD

Interrupt from pad, before override applied

RO

0x0

23:20

Reserved

 

-

-

19

INTOPERI

Input signal to peripheral, after override applied

RO

0x0

18

Reserved

 

-

-

17

INFROMPAD

Input signal from pad, before override applied

RO

0x0

16:14

Reserved

 

-

-

13

OETOPAD

Output enable to pad, after override applied

RO

0x0

12

OEFROMPERI

Output enable from selected peripheral, before override applied

RO

0x0

11:10

Reserved

 

-

-

9

OUTTOPAD

Output signal to pad after override applied

RO

0x0

8

OUTFROMPERI

Output signal from selected peripheral, before override applied

RO

0x0

7:0

Reserved

 

-

-

 

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:

#include <stdio.h>
#include "pico/stdlib.h"
int main()
{
stdio_init_all(); uint32_t *addrGP0Status=(uint32_t*) 0x40014000; uint32_t value=*addrGP0Status; printf("%b",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.

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 ( Tuesday, 21 February 2023 )