Compare commits

...

10 Commits

Author SHA1 Message Date
MReenen
c347cb78e0 long lasting updates 2024-02-26 16:25:30 +01:00
MReenen
41c6e68fc4 some miner changes 2022-08-31 15:04:08 +02:00
MReenen
ba4caba4f0 radio: update 2022-08-31 15:03:47 +02:00
MReenen
fbc9e9f4fb radio: inital commit 2022-08-30 14:54:10 +02:00
MReenen
7f12071e51 remove some example stuff 2022-08-30 14:52:23 +02:00
MReenen
ca6eb091a6 add all build stuff in gitignore 2022-08-30 14:43:28 +02:00
MReenen
61f891433f remove examples 2022-08-30 14:39:01 +02:00
Brian Cooke
a7ad17156b
fix links to pico_w examples (#229)
Fixes #228
2022-07-01 08:01:37 -05:00
graham sanderson
01e8128953 Add Pico W examples 2022-06-29 23:12:10 -05:00
Andrew Scheller
a7ce7007ff
Update spi_master_slave README (#216)
The "List of Files" section should only list text-files (i.e. source code), not images or supplementary files
2022-05-17 22:09:59 -05:00
338 changed files with 700 additions and 30175 deletions

14
.gitignore vendored
View File

@ -5,3 +5,17 @@ cmake-*
build
.DS_Store
*.pdf
CMakeFiles/
Makefile
*.bin
*.dis
*.elf
*.elf.map
*.hex
*.uf2
cmake_install.cmake
elf2uf2/
/generated
/pico-sdk
/CMakeCache.txt

View File

@ -11,43 +11,19 @@ if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})
# Initialize the SDK
pico_sdk_init()
include(example_auto_set_url.cmake)
# Add blink example
add_subdirectory(blink)
# Add hello world example
add_subdirectory(hello_world)
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that aren't called
#-Wno-unused-function # we have some for the docs that aren't called
-Wno-maybe-uninitialized
-Wno-comment
)
# Hardware-specific examples in subdirectories:
add_subdirectory(adc)
add_subdirectory(clocks)
add_subdirectory(cmake)
add_subdirectory(divider)
add_subdirectory(dma)
add_subdirectory(flash)
add_subdirectory(gpio)
add_subdirectory(i2c)
add_subdirectory(interp)
add_subdirectory(multicore)
add_subdirectory(picoboard)
add_subdirectory(pio)
add_subdirectory(pwm)
add_subdirectory(reset)
add_subdirectory(rtc)
add_subdirectory(spi)
add_subdirectory(system)
add_subdirectory(timer)
add_subdirectory(uart)
add_subdirectory(usb)
add_subdirectory(watchdog)
# add all project dirs
add_subdirectory(radio)

View File

@ -108,6 +108,32 @@ App|Description
[blinky](picoboard/blinky)| Blink "hello, world" in Morse code on Pico's LED
[button](picoboard/button)| Use Pico's BOOTSEL button as a regular button input, by temporarily suspending flash access.
### Pico W Networking
These eaxmples are for the Pico W, and are only available for `PICO_BOARD=pico_w`
App|Description
---|---
[picow_access_point](pico_w/access_point)| Starts a WiFi access point, and fields DHCP requests.
[picow_blink](pico_w/blink)| Blinks the on-board LED (which is connected via the WiFi chip).
[picow_iperf_server](pico_w/iperf)| Runs an "iperf" server for WiFi speed testing.
[picow_ntp_client](pico_w/ntp_client)| Connects to an NTP server to fetch and display the current time.
[picow_tcp_client](pico_w/tcp_client)| A simple TCP client. You can run [python_test_tcp_server.py](pico_w/python_test_tcp/python_test_tcp_server.py) for it to connect to.
[picow_tcp_server](pico_w/tcp_server)| A simple TCP server. You can use [python_test_tcp_client.py](pico_w/python_test_tcp/python_test_tcp_client.py) to connect to it.
[picow_wifi_scan](pico_w/wifi_scan)| Scans for WiFi networks and prints the results.
#### FreeRTOS examples
These are examples of integrating Pico W networking under FreeRTOS, and require you to set the `FREERTOS_KERNEL_PATH`
to point to the FreeRTOS Kernel.
App|Description
---|---
[picow_freertos_iperf_server_nosys](pico_w/freertos/iperf)| Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=1 mode. The LED is blinked in another task
[picow_freertos_iperf_server_sys](pico_w/freertos/iperf)| Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The LED is blinked in another task
[picow_freertos_ping_nosys](pico_w/freertos/ping)| Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=1 mode.
[picow_freertos_iperf_server_sys](pico_w/freertos/iperf)| Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The test app uses the lwIP \em socket API in this case.
### PIO
App|Description

View File

@ -1,8 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(adc_console)
add_subdirectory(dma_capture)
add_subdirectory(hello_adc)
add_subdirectory(joystick_display)
add_subdirectory(onboard_temperature)
add_subdirectory(microphone_adc)
endif ()

View File

@ -1,12 +0,0 @@
add_executable(adc_console
adc_console.c
)
target_link_libraries(adc_console pico_stdlib hardware_adc)
# create map/bin/hex file etc.
pico_add_extra_outputs(adc_console)
# add url via pico_set_program_url
example_auto_set_url(adc_console)

View File

@ -1,100 +0,0 @@
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#define N_SAMPLES 1000
uint16_t sample_buf[N_SAMPLES];
void printhelp() {
puts("\nCommands:");
puts("c0, ...\t: Select ADC channel n");
puts("s\t: Sample once");
puts("S\t: Sample many");
puts("w\t: Wiggle pins");
}
void __not_in_flash_func(adc_capture)(uint16_t *buf, size_t count) {
adc_fifo_setup(true, false, 0, false, false);
adc_run(true);
for (int i = 0; i < count; i = i + 1)
buf[i] = adc_fifo_get_blocking();
adc_run(false);
adc_fifo_drain();
}
int main(void) {
stdio_init_all();
adc_init();
adc_set_temp_sensor_enabled(true);
// Set all pins to input (as far as SIO is concerned)
gpio_set_dir_all_bits(0);
for (int i = 2; i < 30; ++i) {
gpio_set_function(i, GPIO_FUNC_SIO);
if (i >= 26) {
gpio_disable_pulls(i);
gpio_set_input_enabled(i, false);
}
}
printf("\n===========================\n");
printf("RP2040 ADC and Test Console\n");
printf("===========================\n");
printhelp();
while (1) {
char c = getchar();
printf("%c", c);
switch (c) {
case 'c':
c = getchar();
printf("%c\n", c);
if (c < '0' || c > '7') {
printf("Unknown input channel\n");
printhelp();
} else {
adc_select_input(c - '0');
printf("Switched to channel %c\n", c);
}
break;
case 's': {
uint32_t result = adc_read();
const float conversion_factor = 3.3f / (1 << 12);
printf("\n0x%03x -> %f V\n", result, result * conversion_factor);
break;
}
case 'S': {
printf("\nStarting capture\n");
adc_capture(sample_buf, N_SAMPLES);
printf("Done\n");
for (int i = 0; i < N_SAMPLES; i = i + 1)
printf("%03x\n", sample_buf[i]);
break;
}
case 'w':
printf("\nPress any key to stop wiggling\n");
int i = 1;
gpio_set_dir_all_bits(-1);
while (getchar_timeout_us(0) == PICO_ERROR_TIMEOUT) {
// Pattern: Flash all pins for a cycle,
// Then scan along pins for one cycle each
i = i ? i << 1 : 1;
gpio_put_all(i ? i : ~0);
}
gpio_set_dir_all_bits(0);
printf("Wiggling halted.\n");
break;
case '\n':
case '\r':
break;
case 'h':
printhelp();
break;
default:
printf("\nUnrecognised command: %c\n", c);
printhelp();
break;
}
}
}

View File

@ -1,20 +0,0 @@
add_executable(adc_dma_capture
dma_capture.c
)
pico_generate_pio_header(adc_dma_capture ${CMAKE_CURRENT_LIST_DIR}/resistor_dac.pio)
target_link_libraries(adc_dma_capture
pico_stdlib
hardware_adc
hardware_dma
# For the dummy output:
hardware_pio
pico_multicore
)
# create map/bin/hex file etc.
pico_add_extra_outputs(adc_dma_capture)
# add url via pico_set_program_url
example_auto_set_url(adc_dma_capture)

View File

@ -1,136 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
// For ADC input:
#include "hardware/adc.h"
#include "hardware/dma.h"
// For resistor DAC output:
#include "pico/multicore.h"
#include "hardware/pio.h"
#include "resistor_dac.pio.h"
// This example uses the DMA to capture many samples from the ADC.
//
// - We are putting the ADC in free-running capture mode at 0.5 Msps
//
// - A DMA channel will be attached to the ADC sample FIFO
//
// - Configure the ADC to right-shift samples to 8 bits of significance, so we
// can DMA into a byte buffer
//
// This could be extended to use the ADC's round robin feature to sample two
// channels concurrently at 0.25 Msps each.
//
// It would be nice to have some analog samples to measure! This example also
// drives waves out through a 5-bit resistor DAC, as found on the reference
// VGA board. If you have that board, you can take an M-F jumper wire from
// GPIO 26 to the Green pin on the VGA connector (top row, next-but-rightmost
// hole). Or you can ignore that part of the code and connect your own signal
// to the ADC input.
// Channel 0 is GPIO26
#define CAPTURE_CHANNEL 0
#define CAPTURE_DEPTH 1000
uint8_t capture_buf[CAPTURE_DEPTH];
void core1_main();
int main() {
stdio_init_all();
// Send core 1 off to start driving the "DAC" whilst we configure the ADC.
multicore_launch_core1(core1_main);
// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.
adc_gpio_init(26 + CAPTURE_CHANNEL);
adc_init();
adc_select_input(CAPTURE_CHANNEL);
adc_fifo_setup(
true, // Write each completed conversion to the sample FIFO
true, // Enable DMA data request (DREQ)
1, // DREQ (and IRQ) asserted when at least 1 sample present
false, // We won't see the ERR bit because of 8 bit reads; disable.
true // Shift each sample to 8 bits when pushing to FIFO
);
// Divisor of 0 -> full speed. Free-running capture with the divider is
// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
// cycles (div not necessarily an integer). Each conversion takes 96
// cycles, so in general you want a divider of 0 (hold down the button
// continuously) or > 95 (take samples less frequently than 96 cycle
// intervals). This is all timed by the 48 MHz ADC clock.
adc_set_clkdiv(0);
printf("Arming DMA\n");
sleep_ms(1000);
// Set up the DMA to start transferring data as soon as it appears in FIFO
uint dma_chan = dma_claim_unused_channel(true);
dma_channel_config cfg = dma_channel_get_default_config(dma_chan);
// Reading from constant address, writing to incrementing byte addresses
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
channel_config_set_read_increment(&cfg, false);
channel_config_set_write_increment(&cfg, true);
// Pace transfers based on availability of ADC samples
channel_config_set_dreq(&cfg, DREQ_ADC);
dma_channel_configure(dma_chan, &cfg,
capture_buf, // dst
&adc_hw->fifo, // src
CAPTURE_DEPTH, // transfer count
true // start immediately
);
printf("Starting capture\n");
adc_run(true);
// Once DMA finishes, stop any new conversions from starting, and clean up
// the FIFO in case the ADC was still mid-conversion.
dma_channel_wait_for_finish_blocking(dma_chan);
printf("Capture finished\n");
adc_run(false);
adc_fifo_drain();
// Print samples to stdout so you can display them in pyplot, excel, matlab
for (int i = 0; i < CAPTURE_DEPTH; ++i) {
printf("%-3d, ", capture_buf[i]);
if (i % 10 == 9)
printf("\n");
}
}
// ----------------------------------------------------------------------------
// Code for driving the "DAC" output for us to measure
// Core 1 is just going to sit and drive samples out continously. PIO provides
// consistent sample frequency.
#define OUTPUT_FREQ_KHZ 5
#define SAMPLE_WIDTH 5
// This is the green channel on the VGA board
#define DAC_PIN_BASE 6
void core1_main() {
PIO pio = pio0;
uint sm = pio_claim_unused_sm(pio0, true);
uint offset = pio_add_program(pio0, &resistor_dac_5bit_program);
resistor_dac_5bit_program_init(pio0, sm, offset,
OUTPUT_FREQ_KHZ * 1000 * 2 * (1 << SAMPLE_WIDTH), DAC_PIN_BASE);
while (true) {
// Triangle wave
for (int i = 0; i < (1 << SAMPLE_WIDTH); ++i)
pio_sm_put_blocking(pio, sm, i);
for (int i = 0; i < (1 << SAMPLE_WIDTH); ++i)
pio_sm_put_blocking(pio, sm, (1 << SAMPLE_WIDTH) - 1 - i);
}
}

View File

@ -1,38 +0,0 @@
;
; Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program resistor_dac_5bit
; Drive one of the 5-bit resistor DACs on the VGA reference board. (this isn't
; a good way to do VGA -- just want a nice sawtooth for the ADC example!)
out pins, 5
% c-sdk {
#include "hardware/clocks.h"
static inline void resistor_dac_5bit_program_init(PIO pio, uint sm, uint offset,
uint sample_rate_hz, uint pin_base) {
pio_sm_set_pins_with_mask(pio, sm, 0, 0x1fu << pin_base);
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, 0x1fu << pin_base);
for (int i = 0; i < 5; ++i)
pio_gpio_init(pio, pin_base + i);
pio_sm_config c = resistor_dac_5bit_program_get_default_config(offset);
sm_config_set_out_pins(&c, pin_base, 5);
// Shift to right, autopull threshold 5
sm_config_set_out_shift(&c, true, true, 5);
// Deeper FIFO as we're not doing any RX
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
float div = (float)clock_get_hz(clk_sys) / sample_rate_hz;
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}

View File

@ -1,11 +0,0 @@
add_executable(hello_adc
hello_adc.c
)
target_link_libraries(hello_adc pico_stdlib hardware_adc)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_adc)
# add url via pico_set_program_url
example_auto_set_url(hello_adc)

View File

@ -1,30 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
printf("ADC Example, measuring GPIO26\n");
adc_init();
// Make sure GPIO is high-impedance, no pullups etc
adc_gpio_init(26);
// Select ADC input 0 (GPIO26)
adc_select_input(0);
while (1) {
// 12-bit conversion, assume max value == ADC_VREF == 3.3 V
const float conversion_factor = 3.3f / (1 << 12);
uint16_t result = adc_read();
printf("Raw value: 0x%03x, voltage: %f V\n", result, result * conversion_factor);
sleep_ms(500);
}
}

View File

@ -1,11 +0,0 @@
add_executable(joystick_display
joystick_display.c
)
target_link_libraries(joystick_display pico_stdlib hardware_adc)
# create map/bin/hex file etc.
pico_add_extra_outputs(joystick_display)
# add url via pico_set_program_url
example_auto_set_url(joystick_display)

View File

@ -1,40 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
// Make sure GPIO is high-impedance, no pullups etc
adc_gpio_init(26);
adc_gpio_init(27);
while (1) {
adc_select_input(0);
uint adc_x_raw = adc_read();
adc_select_input(1);
uint adc_y_raw = adc_read();
// Display the joystick position something like this:
// X: [ o ] Y: [ o ]
const uint bar_width = 40;
const uint adc_max = (1 << 12) - 1;
uint bar_x_pos = adc_x_raw * bar_width / adc_max;
uint bar_y_pos = adc_y_raw * bar_width / adc_max;
printf("\rX: [");
for (int i = 0; i < bar_width; ++i)
putchar( i == bar_x_pos ? 'o' : ' ');
printf("] Y: [");
for (int i = 0; i < bar_width; ++i)
putchar( i == bar_y_pos ? 'o' : ' ');
printf("]");
sleep_ms(50);
}
}

View File

@ -1,12 +0,0 @@
add_executable(microphone_adc
microphone_adc.c
)
# pull in common dependencies and adc hardware support
target_link_libraries(microphone_adc pico_stdlib hardware_adc)
# create map/bin/hex file etc.
pico_add_extra_outputs(microphone_adc)
# add url via pico_set_program_url
example_auto_set_url(microphone_adc)

View File

@ -1,48 +0,0 @@
= Attaching a microphone using the ADC
This example code shows how to interface the Raspberry Pi Pico with a standard analog microphone via the onboard analog to digital converter (ADC). In this example, we use an ICS-40180 breakout board by SparkFun but any analog microphone should be compatible with this tutorial. SparkFun have https://learn.sparkfun.com/tutorials/mems-microphone-hookup-guide[written a guide] for this board that goes into more detail about the board and how it works.
[TIP]
======
An analog to digital converter (ADC) is responsible for reading continually varying input signals that may range from 0 to a specified reference voltage (in the Pico's case this reference voltage is set by the supply voltage and can be measured on pin 35, ADC_VREF) and converting them into binary, i.e. a number that can be digitally stored.
======
The Pico has a 12-bit ADC (ENOB of 8.7-bit, see https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf[RP2040 datasheet section 4.9.3 for more details]), meaning that a read operation will return a number ranging from 0 to 4095 (2^12 - 1) for a total of 4096 possible values. Therefore, the resolution of the ADC is 3.3/4096, so roughly steps of 0.8 millivolts. The SparkFun breakout uses an OPA344 operational amplifier to boost the signal coming from the microphone to voltage levels that can be easily read by the ADC. An important side effect is that a bias of 0.5*Vcc is added to the signal, even when the microphone is not picking up any sound.
The ADC provides us with a raw voltage value but when dealing with sound, we're more interested in the amplitude of the audio signal. This is defined as one half the peak-to-peak amplitude. Included with this example is a very simple Python script that will plot the voltage values it receives via the serial port. By tweaking the sampling rates, and various other parameters, the data from the microphone can be analysed in various ways, such as in a Fast Fourier Transform to see what frequencies make up the signal.
[[microphone_adc_plotter_image]]
[pdfwidth=75%]
.Example output from included Python script
image::microphone_adc_plotter.png[]
== Wiring information
Wiring up the device requires 3 jumpers, to connect VCC (3.3v), GND, and AOUT. The example here uses ADC0, which is GP26. Power is supplied from the 3.3V pin.
WARNING: Most boards will take a range of VCC voltages from the Pico's default 3.3V to the 5 volts commonly seen on other microcontrollers. Ensure your board doesn't output an analogue signal greater than 3.3V as this may result in permanent damage to the Pico's ADC.
[[ics-40180-adc_wiring]]
[pdfwidth=75%]
.Wiring Diagram for ICS-40180 microphone breakout board.
image::microphone_adc_bb.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
microphone_adc.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[ics-40180-adc-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| ICS-40180 microphone breakout board or similar | 1 | https://www.sparkfun.com/products/18011[From SparkFun]
| M/M Jumper wires | 3 | generic part
|===

View File

@ -1,49 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "hardware/uart.h"
#include "pico/binary_info.h"
/* Example code to extract analog values from a microphone using the ADC
with accompanying Python file to plot these values
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO 26/ADC0 (pin 31)-> AOUT or AUD on microphone board
3.3v (pin 36) -> VCC on microphone board
GND (pin 38) -> GND on microphone board
*/
#define ADC_NUM 0
#define ADC_PIN (26 + ADC_NUM)
#define ADC_VREF 3.3
#define ADC_RANGE (1 << 12)
#define ADC_CONVERT (ADC_VREF / (ADC_RANGE - 1))
int main() {
stdio_init_all();
printf("Beep boop, listening...\n");
bi_decl(bi_program_description("Analog microphone example for Raspberry Pi Pico")); // for picotool
bi_decl(bi_1pin_with_name(ADC_PIN, "ADC input pin"));
adc_init();
adc_gpio_init( ADC_PIN);
adc_select_input( ADC_NUM);
uint adc_raw;
while (1) {
adc_raw = adc_read(); // raw voltage from ADC
printf("%.2f\n", adc_raw * ADC_CONVERT);
sleep_ms(10);
}
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

View File

@ -1,77 +0,0 @@
#!/usr/bin/env python3
# Grabs raw data from the Pico's UART and plots it as received
# Install dependencies:
# python3 -m pip install pyserial matplotlib
# Usage: python3 plotter <port>
# eg. python3 plotter /dev/ttyACM0
# see matplotlib animation API for more: https://matplotlib.org/stable/api/animation_api.html
import serial
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.lines import Line2D
# disable toolbar
plt.rcParams['toolbar'] = 'None'
class Plotter:
def __init__(self, ax):
self.ax = ax
self.maxt = 250
self.tdata = [0]
self.ydata = [3.3/2]
self.line = Line2D(self.tdata, self.ydata)
self.ax.add_line(self.line)
self.ax.set_ylim(0, 3.3)
self.ax.set_xlim(0, self.maxt)
def update(self, y):
lastt = self.tdata[-1]
if lastt - self.tdata[0] >= self.maxt: # drop old frames
self.tdata = self.tdata[1:]
self.ydata = self.ydata[1:]
self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt)
t = lastt + 1
self.tdata.append(t)
self.ydata.append(y)
self.line.set_data(self.tdata, self.ydata)
return self.line,
def serial_getter():
# grab fresh ADC values
# note sometimes UART drops chars so we try a max of 5 times
# to get proper data
while True:
for i in range(5):
line = ser.readline()
try:
line = float(line)
except ValueError:
continue
break
yield line
if len(sys.argv) < 2:
raise Exception("Ruh roh..no port specified!")
ser = serial.Serial(sys.argv[1], 115200, timeout=1)
fig, ax = plt.subplots()
plotter = Plotter(ax)
ani = animation.FuncAnimation(fig, plotter.update, serial_getter, interval=1,
blit=True, cache_frame_data=False)
ax.set_xlabel("Samples")
ax.set_ylabel("Voltage (V)")
fig.canvas.manager.set_window_title('Microphone ADC example')
fig.tight_layout()
plt.show()

View File

@ -1,14 +0,0 @@
add_executable(onboard_temperature onboard_temperature.c)
target_link_libraries(onboard_temperature pico_stdlib hardware_adc)
# enable uart output, disable usb output
pico_enable_stdio_uart(onboard_temperature 1)
pico_enable_stdio_usb(onboard_temperature 0)
# create map/bin/hex file etc.
pico_add_extra_outputs(onboard_temperature)
# add url via pico_set_program_url
example_auto_set_url(onboard_temperature)

View File

@ -1,63 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
/* Choose 'C' for Celsius or 'F' for Fahrenheit. */
#define TEMPERATURE_UNITS 'C'
/* References for this implementation:
* raspberry-pi-pico-c-sdk.pdf, Section '4.1.1. hardware_adc'
* pico-examples/adc/adc_console/adc_console.c */
float read_onboard_temperature(const char unit) {
/* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */
const float conversionFactor = 3.3f / (1 << 12);
float adc = (float)adc_read() * conversionFactor;
float tempC = 27.0f - (adc - 0.706f) / 0.001721f;
if (unit == 'C') {
return tempC;
} else if (unit == 'F') {
return tempC * 9 / 5 + 32;
}
return -1.0f;
}
int main() {
stdio_init_all();
#ifdef PICO_DEFAULT_LED_PIN
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
#endif
/* Initialize hardware AD converter, enable onboard temperature sensor and
* select its channel (do this once for efficiency, but beware that this
* is a global operation). */
adc_init();
adc_set_temp_sensor_enabled(true);
adc_select_input(4);
while (true) {
float temperature = read_onboard_temperature(TEMPERATURE_UNITS);
printf("Onboard temperature = %.02f %c\n", temperature, TEMPERATURE_UNITS);
#ifdef PICO_DEFAULT_LED_PIN
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(10);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
#endif
sleep_ms(990);
}
return 0;
}

View File

@ -7,6 +7,3 @@ target_link_libraries(blink pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(blink)
# add url via pico_set_program_url
example_auto_set_url(blink)

View File

@ -1,6 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(detached_clk_peri)
add_subdirectory(hello_48MHz)
add_subdirectory(hello_gpout)
add_subdirectory(hello_resus)
endif ()

View File

@ -1,12 +0,0 @@
add_executable(clocks_detached_clk_peri
detached_clk_peri.c
)
# pull in common dependencies
target_link_libraries(clocks_detached_clk_peri pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(clocks_detached_clk_peri)
# add url via pico_set_program_url
example_auto_set_url(clocks_detached_clk_peri)

View File

@ -1,86 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// By default, clk_peri (which drives the serial parts of SPI and UART) is
// attached directly to clk_sys, so varies if the system clock is scaled up
// and down. clk_peri has a multiplexer (though no divider) which allows it to
// be attached to other sources.
//
// If set_sys_clock_khz is called (here setting the system clock to 133 MHz),
// this automatically attaches clk_peri to the USB PLL, which by default we run
// at 48 MHz. As long as you call this *before* configuring your UART etc, the
// UART baud rate will then not be affected by subsequent changes to clk_sys.
//
// However, dropping clk_peri to 48 MHz limits the maximum serial frequencies
// that can be attained by UART and particularly SPI. This example shows how
// clk_peri can be attached directly to the system PLL, and the clk_sys
// divider can then be varied to scale the system (CPUs, DMA, bus fabric etc)
// frequency up and down whilst keeping clk_peri at a constant 133 MHz.
//
// The complete list of clock sources available on clk_peri can be found in
// hardware/regs/clocks.h:
//
// Field : CLOCKS_CLK_PERI_CTRL_AUXSRC
// 0x0 -> clk_sys
// 0x1 -> clksrc_pll_sys
// 0x2 -> clksrc_pll_usb
// 0x3 -> rosc_clksrc_ph
// 0x4 -> xosc_clksrc
// 0x5 -> clksrc_gpin0
// 0x6 -> clksrc_gpin1
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#define PLL_SYS_KHZ (133 * 1000)
int main() {
// Set the system frequency to 133 MHz. vco_calc.py from the SDK tells us
// this is exactly attainable at the PLL from a 12 MHz crystal: FBDIV =
// 133 (so VCO of 1596 MHz), PD1 = 6, PD2 = 2. This function will set the
// system PLL to 133 MHz and set the clk_sys divisor to 1.
set_sys_clock_khz(PLL_SYS_KHZ, true);
// The previous line automatically detached clk_peri from clk_sys, and
// attached it to pll_usb, so that clk_peri won't be disturbed by future
// changes to system clock or system PLL. If we need higher clk_peri
// frequencies, we can attach clk_peri directly back to system PLL (no
// divider available) and then use the clk_sys divider to scale clk_sys
// independently of clk_peri.
clock_configure(
clk_peri,
0, // No glitchless mux
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
PLL_SYS_KHZ * 1000, // Input frequency
PLL_SYS_KHZ * 1000 // Output (must be same as no divider)
);
// The serial clock won't vary from this point onward, so we can configure
// the UART etc.
stdio_init_all();
puts("Peripheral clock is attached directly to system PLL.");
puts("We can vary the system clock divisor while printing from the UART:");
for (uint div = 1; div <= 10; ++div) {
printf("Setting system clock divisor to %u\n", div);
clock_configure(
clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
PLL_SYS_KHZ,
PLL_SYS_KHZ / div
);
printf("Measuring system clock with frequency counter:");
// Note that the numbering of frequency counter sources is not the
// same as the numbering of clock slice register blocks. (If we passed
// the clk_sys enum here we would actually end up measuring XOSC.)
printf("%u kHz\n", frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS));
}
return 0;
}

View File

@ -1,12 +0,0 @@
add_executable(hello_48MHz
hello_48MHz.c
)
# pull in common dependencies and additional clocks hardware support
target_link_libraries(hello_48MHz pico_stdlib hardware_clocks)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_48MHz)
# add url via pico_set_program_url
example_auto_set_url(hello_48MHz)

View File

@ -1,68 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pll.h"
#include "hardware/clocks.h"
#include "hardware/structs/pll.h"
#include "hardware/structs/clocks.h"
void measure_freqs(void) {
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
printf("pll_sys = %dkHz\n", f_pll_sys);
printf("pll_usb = %dkHz\n", f_pll_usb);
printf("rosc = %dkHz\n", f_rosc);
printf("clk_sys = %dkHz\n", f_clk_sys);
printf("clk_peri = %dkHz\n", f_clk_peri);
printf("clk_usb = %dkHz\n", f_clk_usb);
printf("clk_adc = %dkHz\n", f_clk_adc);
printf("clk_rtc = %dkHz\n", f_clk_rtc);
// Can't measure clk_ref / xosc as it is the ref
}
int main() {
stdio_init_all();
printf("Hello, world!\n");
measure_freqs();
// Change clk_sys to be 48MHz. The simplest way is to take this from PLL_USB
// which has a source frequency of 48MHz
clock_configure(clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
48 * MHZ,
48 * MHZ);
// Turn off PLL sys for good measure
pll_deinit(pll_sys);
// CLK peri is clocked from clk_sys so need to change clk_peri's freq
clock_configure(clk_peri,
0,
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
48 * MHZ,
48 * MHZ);
// Re init uart now that clk_peri has changed
stdio_init_all();
measure_freqs();
printf("Hello, 48MHz");
return 0;
}

View File

@ -1,12 +0,0 @@
add_executable(hello_gpout
hello_gpout.c
)
# pull in common dependencies
target_link_libraries(hello_gpout pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_gpout)
# add url via pico_set_program_url
example_auto_set_url(hello_gpout)

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/clocks.h"
int main() {
stdio_init_all();
printf("Hello gpout\n");
// Output clk_sys / 10 to gpio 21, etc...
clock_gpio_init(21, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_CLK_SYS, 10);
clock_gpio_init(23, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_CLK_USB, 10);
clock_gpio_init(24, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_CLK_ADC, 10);
clock_gpio_init(26, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_CLK_RTC, 10);
return 0;
}

View File

@ -1,12 +0,0 @@
add_executable(hello_resus
hello_resus.c
)
# pull in common dependencies
target_link_libraries(hello_resus pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_resus)
# add url via pico_set_program_url
example_auto_set_url(hello_resus)

View File

@ -1,48 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "hardware/pll.h"
volatile bool seen_resus;
void resus_callback(void) {
// Reconfigure PLL sys back to the default state of 1500 / 6 / 2 = 125MHz
pll_init(pll_sys, 1, 1500 * MHZ, 6, 2);
// CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
clock_configure(clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
125 * MHZ,
125 * MHZ);
// Reconfigure uart as clocks have changed
stdio_init_all();
printf("Resus event fired\n");
// Wait for uart output to finish
uart_default_tx_wait_blocking();
seen_resus = true;
}
int main() {
stdio_init_all();
printf("Hello resus\n");
seen_resus = false;
clocks_enable_resus(&resus_callback);
// Break PLL sys
pll_deinit(pll_sys);
while(!seen_resus);
return 0;
}

View File

@ -1,12 +0,0 @@
add_executable(hello_divider
hello_divider.c
)
# pull in common dependencies
target_link_libraries(hello_divider pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_divider)
# add url via pico_set_program_url
example_auto_set_url(hello_divider)

View File

@ -1,75 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/divider.h"
/// \tag::hello_divider[]
int main() {
stdio_init_all();
printf("Hello, divider!\n");
// This is the basic hardware divider function
int32_t dividend = 123456;
int32_t divisor = -321;
divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);
printf("%d/%d = %d remainder %d\n", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));
// Is it right?
printf("Working backwards! Result %d should equal %d!\n\n",
to_quotient_s32(result) * divisor + to_remainder_s32(result), dividend);
// This is the recommended unsigned fast divider for general use.
int32_t udividend = 123456;
int32_t udivisor = 321;
divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);
printf("%d/%d = %d remainder %d\n", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));
// Is it right?
printf("Working backwards! Result %d should equal %d!\n\n",
to_quotient_u32(result) * divisor + to_remainder_u32(result), dividend);
// You can also do divides asynchronously. Divides will be complete after 8 cyles.
hw_divider_divmod_s32_start(dividend, divisor);
// Do something for 8 cycles!
// In this example, our results function will wait for completion.
// Use hw_divider_result_nowait() if you don't want to wait, but are sure you have delayed at least 8 cycles
result = hw_divider_result_wait();
printf("Async result %d/%d = %d remainder %d\n", dividend, divisor, to_quotient_s32(result),
to_remainder_s32(result));
// For a really fast divide, you can use the inlined versions... the / involves a function call as / always does
// when using the ARM AEABI, so if you really want the best performance use the inlined versions.
// Note that the / operator function DOES use the hardware divider by default, although you can change
// that behavior by calling pico_set_divider_implementation in the cmake build for your target.
printf("%d / %d = (by operator %d) (inlined %d)\n", dividend, divisor,
dividend / divisor, hw_divider_s32_quotient_inlined(dividend, divisor));
// Note however you must manually save/restore the divider state if you call the inlined methods from within an IRQ
// handler.
hw_divider_state_t state;
hw_divider_divmod_s32_start(dividend, divisor);
hw_divider_save_state(&state);
hw_divider_divmod_s32_start(123, 7);
printf("inner %d / %d = %d\n", 123, 7, hw_divider_s32_quotient_wait());
hw_divider_restore_state(&state);
int32_t tmp = hw_divider_s32_quotient_wait();
printf("outer divide %d / %d = %d\n", dividend, divisor, tmp);
return 0;
}
/// \end::hello_divider[]

View File

@ -1,5 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(channel_irq)
add_subdirectory(control_blocks)
add_subdirectory(hello_dma)
endif ()

View File

@ -1,18 +0,0 @@
add_executable(dma_channel_irq
channel_irq.c
)
pico_generate_pio_header(dma_channel_irq ${CMAKE_CURRENT_LIST_DIR}/pio_serialiser.pio)
target_link_libraries(dma_channel_irq
pico_stdlib
hardware_dma
hardware_irq
hardware_pio
)
# create map/bin/hex file etc.
pico_add_extra_outputs(dma_channel_irq)
# add url via pico_set_program_url
example_auto_set_url(dma_channel_irq)

View File

@ -1,94 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Show how to reconfigure and restart a channel in a channel completion
// interrupt handler.
//
// Our DMA channel will transfer data to a PIO state machine, which is
// configured to serialise the raw bits that we push, one by one. We're going
// to use this to do some crude LED PWM by repeatedly sending values with the
// right balance of 1s and 0s. (note there are better ways to do PWM with PIO
// -- see the PIO PWM example).
//
// Once the channel has sent a predetermined amount of data, it will halt, and
// raise an interrupt flag. The processor will enter the interrupt handler in
// response to this, where it will reconfigure and restart the channel. This
// repeats.
#include <stdio.h>
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "pio_serialiser.pio.h"
// PIO sends one bit per 10 system clock cycles. DMA sends the same 32-bit
// value 10 000 times before halting. This means we cycle through the 32 PWM
// levels roughly once per second.
#define PIO_SERIAL_CLKDIV 10.f
#define PWM_REPEAT_COUNT 10000
#define N_PWM_LEVELS 32
int dma_chan;
void dma_handler() {
static int pwm_level = 0;
static uint32_t wavetable[N_PWM_LEVELS];
static bool first_run = true;
// Entry number `i` has `i` one bits and `(32 - i)` zero bits.
if (first_run) {
first_run = false;
for (int i = 0; i < N_PWM_LEVELS; ++i)
wavetable[i] = ~(~0u << i);
}
// Clear the interrupt request.
dma_hw->ints0 = 1u << dma_chan;
// Give the channel a new wave table entry to read from, and re-trigger it
dma_channel_set_read_addr(dma_chan, &wavetable[pwm_level], true);
pwm_level = (pwm_level + 1) % N_PWM_LEVELS;
}
int main() {
#ifndef PICO_DEFAULT_LED_PIN
#warning dma/channel_irq example requires a board with a regular LED
#else
// Set up a PIO state machine to serialise our bits
uint offset = pio_add_program(pio0, &pio_serialiser_program);
pio_serialiser_program_init(pio0, 0, offset, PICO_DEFAULT_LED_PIN, PIO_SERIAL_CLKDIV);
// Configure a channel to write the same word (32 bits) repeatedly to PIO0
// SM0's TX FIFO, paced by the data request signal from that peripheral.
dma_chan = dma_claim_unused_channel(true);
dma_channel_config c = dma_channel_get_default_config(dma_chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_read_increment(&c, false);
channel_config_set_dreq(&c, DREQ_PIO0_TX0);
dma_channel_configure(
dma_chan,
&c,
&pio0_hw->txf[0], // Write address (only need to set this once)
NULL, // Don't provide a read address yet
PWM_REPEAT_COUNT, // Write the same value many times, then halt and interrupt
false // Don't start yet
);
// Tell the DMA to raise IRQ line 0 when the channel finishes a block
dma_channel_set_irq0_enabled(dma_chan, true);
// Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
irq_set_enabled(DMA_IRQ_0, true);
// Manually call the handler once, to trigger the first transfer
dma_handler();
// Everything else from this point is interrupt-driven. The processor has
// time to sit and think about its early retirement -- maybe open a bakery?
while (true)
tight_loop_contents();
#endif
}

View File

@ -1,27 +0,0 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program pio_serialiser
; Just serialise a stream of bits. Take 32 bits from each FIFO record. LSB-first.
.wrap_target
out pins, 1
.wrap
% c-sdk {
static inline void pio_serialiser_program_init(PIO pio, uint sm, uint offset, uint data_pin, float clk_div) {
pio_gpio_init(pio, data_pin);
pio_sm_set_consecutive_pindirs(pio, sm, data_pin, 1, true);
pio_sm_config c = pio_serialiser_program_get_default_config(offset);
sm_config_set_out_pins(&c, data_pin, 1);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_clkdiv(&c, clk_div);
sm_config_set_out_shift(&c, true, true, 32);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}

View File

@ -1,11 +0,0 @@
add_executable(dma_control_blocks
control_blocks.c
)
target_link_libraries(dma_control_blocks pico_stdlib hardware_dma)
# create map/bin/hex file etc.
pico_add_extra_outputs(dma_control_blocks)
# add url via pico_set_program_url
example_auto_set_url(dma_control_blocks)

View File

@ -1,115 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Use two DMA channels to make a programmed sequence of data transfers to the
// UART (a data gather operation). One channel is responsible for transferring
// the actual data, the other repeatedly reprograms that channel.
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/structs/uart.h"
// These buffers will be DMA'd to the UART, one after the other.
const char word0[] = "Transferring ";
const char word1[] = "one ";
const char word2[] = "word ";
const char word3[] = "at ";
const char word4[] = "a ";
const char word5[] = "time.\n";
// Note the order of the fields here: it's important that the length is before
// the read address, because the control channel is going to write to the last
// two registers in alias 3 on the data channel:
// +0x0 +0x4 +0x8 +0xC (Trigger)
// Alias 0: READ_ADDR WRITE_ADDR TRANS_COUNT CTRL
// Alias 1: CTRL READ_ADDR WRITE_ADDR TRANS_COUNT
// Alias 2: CTRL TRANS_COUNT READ_ADDR WRITE_ADDR
// Alias 3: CTRL WRITE_ADDR TRANS_COUNT READ_ADDR
//
// This will program the transfer count and read address of the data channel,
// and trigger it. Once the data channel completes, it will restart the
// control channel (via CHAIN_TO) to load the next two words into its control
// registers.
const struct {uint32_t len; const char *data;} control_blocks[] = {
{count_of(word0) - 1, word0}, // Skip null terminator
{count_of(word1) - 1, word1},
{count_of(word2) - 1, word2},
{count_of(word3) - 1, word3},
{count_of(word4) - 1, word4},
{count_of(word5) - 1, word5},
{0, NULL} // Null trigger to end chain.
};
int main() {
#ifndef uart_default
#warning dma/control_blocks example requires a UART
#else
stdio_init_all();
puts("DMA control block example:");
// ctrl_chan loads control blocks into data_chan, which executes them.
int ctrl_chan = dma_claim_unused_channel(true);
int data_chan = dma_claim_unused_channel(true);
// The control channel transfers two words into the data channel's control
// registers, then halts. The write address wraps on a two-word
// (eight-byte) boundary, so that the control channel writes the same two
// registers when it is next triggered.
dma_channel_config c = dma_channel_get_default_config(ctrl_chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, true);
channel_config_set_ring(&c, true, 3); // 1 << 3 byte boundary on write ptr
dma_channel_configure(
ctrl_chan,
&c,
&dma_hw->ch[data_chan].al3_transfer_count, // Initial write address
&control_blocks[0], // Initial read address
2, // Halt after each control block
false // Don't start yet
);
// The data channel is set up to write to the UART FIFO (paced by the
// UART's TX data request signal) and then chain to the control channel
// once it completes. The control channel programs a new read address and
// data length, and retriggers the data channel.
c = dma_channel_get_default_config(data_chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, uart_get_dreq(uart_default, true));
// Trigger ctrl_chan when data_chan completes
channel_config_set_chain_to(&c, ctrl_chan);
// Raise the IRQ flag when 0 is written to a trigger register (end of chain):
channel_config_set_irq_quiet(&c, true);
dma_channel_configure(
data_chan,
&c,
&uart_get_hw(uart_default)->dr,
NULL, // Initial read address and transfer count are unimportant;
0, // the control channel will reprogram them each time.
false // Don't start yet.
);
// Everything is ready to go. Tell the control channel to load the first
// control block. Everything is automatic from here.
dma_start_channel_mask(1u << ctrl_chan);
// The data channel will assert its IRQ flag when it gets a null trigger,
// indicating the end of the control block list. We're just going to wait
// for the IRQ flag instead of setting up an interrupt handler.
while (!(dma_hw->intr & 1u << data_chan))
tight_loop_contents();
dma_hw->ints0 = 1u << data_chan;
puts("DMA finished.");
#endif
}

View File

@ -1,11 +0,0 @@
add_executable(hello_dma
hello_dma.c
)
target_link_libraries(hello_dma pico_stdlib hardware_dma)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_dma)
# add url via pico_set_program_url
example_auto_set_url(hello_dma)

View File

@ -1,49 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Use the DMA to copy data between two buffers in memory.
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
// Data will be copied from src to dst
const char src[] = "Hello, world! (from DMA)";
char dst[count_of(src)];
int main() {
stdio_init_all();
// Get a free channel, panic() if there are none
int chan = dma_claim_unused_channel(true);
// 8 bit transfers. Both read and write address increment after each
// transfer (each pointing to a location in src or dst respectively).
// No DREQ is selected, so the DMA transfers as fast as it can.
dma_channel_config c = dma_channel_get_default_config(chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, true);
dma_channel_configure(
chan, // Channel to be configured
&c, // The configuration we just created
dst, // The initial write address
src, // The initial read address
count_of(src), // Number of transfers; in this case each is 1 byte.
true // Start immediately.
);
// We could choose to go and do something else whilst the DMA is doing its
// thing. In this case the processor has nothing else to do, so we just
// wait for the DMA to finish.
dma_channel_wait_for_finish_blocking(chan);
// The DMA has now copied our text from the transmit buffer (src) to the
// receive buffer (dst), so we can print it out from there.
puts(dst);
}

View File

@ -1,5 +0,0 @@
set(PICO_EXAMPLE_URL_BASE "https://github.com/raspberrypi/pico-examples/tree/HEAD")
macro(example_auto_set_url TARGET)
file(RELATIVE_PATH URL_REL_PATH "${PICO_EXAMPLES_PATH}" "${CMAKE_CURRENT_LIST_DIR}")
pico_set_program_url(${TARGET} "${PICO_EXAMPLE_URL_BASE}/${URL_REL_PATH}")
endmacro()

View File

@ -1,7 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(cache_perfctr)
add_subdirectory(nuke)
add_subdirectory(program)
add_subdirectory(ssi_dma)
add_subdirectory(xip_stream)
endif ()

View File

@ -1,13 +0,0 @@
add_executable(flash_cache_perfctr
flash_cache_perfctr.c
)
target_link_libraries(flash_cache_perfctr
pico_stdlib
)
# create map/bin/hex file etc.
pico_add_extra_outputs(flash_cache_perfctr)
# add url via pico_set_program_url
example_auto_set_url(flash_cache_perfctr)

View File

@ -1,88 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/structs/xip_ctrl.h"
// Example of using cache hit/access counters, and showing the effect of
// invalidate on cache miss/hit.
const uint32_t test_data[8] = {0, 1, 2, 3, 4, 5, 6, 7};
void __no_inline_not_in_flash_func(check)(bool cond, const char *msg) {
if (!cond) {
puts(msg);
exit(-1);
}
}
void __no_inline_not_in_flash_func(check_hit_miss_invalidate)() {
io_rw_32 *test_data_ptr = (io_rw_32 *) test_data;
/// \tag::check_hit_miss_invalidate[]
// Flush cache to make sure we miss the first time we access test_data
xip_ctrl_hw->flush = 1;
while (!(xip_ctrl_hw->stat & XIP_STAT_FLUSH_READY_BITS))
tight_loop_contents();
// Clear counters (write any value to clear)
xip_ctrl_hw->ctr_acc = 1;
xip_ctrl_hw->ctr_hit = 1;
(void) *test_data_ptr;
check(xip_ctrl_hw->ctr_hit == 0 && xip_ctrl_hw->ctr_acc == 1,
"First access to data should miss");
(void) *test_data_ptr;
check(xip_ctrl_hw->ctr_hit == 1 && xip_ctrl_hw->ctr_acc == 2,
"Second access to data should hit");
// Write to invalidate individual cache lines (64 bits)
// Writes must be directed to the cacheable, allocatable alias (address 0x10.._....)
*test_data_ptr = 0;
(void) *test_data_ptr;
check(xip_ctrl_hw->ctr_hit == 1 && xip_ctrl_hw->ctr_acc == 3,
"Should miss after invalidation");
(void) *test_data_ptr;
check(xip_ctrl_hw->ctr_hit == 2 && xip_ctrl_hw->ctr_acc == 4,
"Second access after invalidation should hit again");
/// \end::check_hit_miss_invalidate[]
}
// Some code which achieves a very high cache hit rate:
int recursive_fibonacci(int n) {
if (n <= 1)
return 1;
else
return recursive_fibonacci(n - 1) + recursive_fibonacci(n - 2);
}
int main() {
stdio_init_all();
uint hit = xip_ctrl_hw->ctr_hit;
uint access = xip_ctrl_hw->ctr_acc;
if (access == 0)
printf("It looks like you're running this example from SRAM. This probably won't go well!\n");
// Note the hit rate will appear quite low at boot, as the .data,
// .time_critical init in crt0 read a lot of read-once data from flash
printf("At boot: %d hits, %d accesses\n", hit, access);
printf("Hit rate so far: %.1f%%\n", hit * 100.f / access);
printf("Calculate 25th fibonacci number: %d\n", recursive_fibonacci(25));
printf("New hit rate after printf and fibonacci: %.1f%%\n", xip_ctrl_hw->ctr_hit * 100.f / xip_ctrl_hw->ctr_acc);
check_hit_miss_invalidate();
printf("Hit/miss check passed\n");
return 0;
}

View File

@ -1,18 +0,0 @@
add_executable(flash_nuke
nuke.c
)
target_link_libraries(flash_nuke
pico_stdlib
hardware_flash
)
# It doesn't make sense to run this program from flash. Always build a
# RAM-only binary.
pico_set_binary_type(flash_nuke no_flash)
pico_add_extra_outputs(flash_nuke)
# add url via pico_set_program_url
example_auto_set_url(flash_nuke)

View File

@ -1,56 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Obliterate the contents of flash. This is a silly thing to do if you are
// trying to run this program from flash, so you should really load and run
// directly from SRAM. You can enable RAM-only builds for all targets by doing:
//
// cmake -DPICO_NO_FLASH=1 ..
//
// in your build directory. We've also forced no-flash builds for this app in
// particular by adding:
//
// pico_set_binary_type(flash_nuke no_flash)
//
// To the CMakeLists.txt app for this file. Just to be sure, we can check the
// define:
#if !PICO_NO_FLASH
#error "This example must be built to run from SRAM!"
#endif
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "pico/bootrom.h"
int main() {
uint flash_size_bytes;
#ifndef PICO_FLASH_SIZE_BYTES
#warning PICO_FLASH_SIZE_BYTES not set, assuming 16M
flash_size_bytes = 16 * 1024 * 1024;
#else
flash_size_bytes = PICO_FLASH_SIZE_BYTES;
#endif
flash_range_erase(0, flash_size_bytes);
// Leave an eyecatcher pattern in the first page of flash so picotool can
// more easily check the size:
static const uint8_t eyecatcher[FLASH_PAGE_SIZE] = "NUKE";
flash_range_program(0, eyecatcher, FLASH_PAGE_SIZE);
#ifdef PICO_DEFAULT_LED_PIN
// Flash LED for success
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
for (int i = 0; i < 3; ++i) {
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(100);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
sleep_ms(100);
}
#endif
// Pop back up as an MSD drive
reset_usb_boot(0, 0);
}

View File

@ -1,14 +0,0 @@
add_executable(flash_program
flash_program.c
)
target_link_libraries(flash_program
pico_stdlib
hardware_flash
)
# create map/bin/hex file etc.
pico_add_extra_outputs(flash_program)
# add url via pico_set_program_url
example_auto_set_url(flash_program)

View File

@ -1,58 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
// We're going to erase and reprogram a region 256k from the start of flash.
// Once done, we can access this at XIP_BASE + 256k.
#define FLASH_TARGET_OFFSET (256 * 1024)
const uint8_t *flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
void print_buf(const uint8_t *buf, size_t len) {
for (size_t i = 0; i < len; ++i) {
printf("%02x", buf[i]);
if (i % 16 == 15)
printf("\n");
else
printf(" ");
}
}
int main() {
stdio_init_all();
uint8_t random_data[FLASH_PAGE_SIZE];
for (int i = 0; i < FLASH_PAGE_SIZE; ++i)
random_data[i] = rand() >> 16;
printf("Generated random data:\n");
print_buf(random_data, FLASH_PAGE_SIZE);
// Note that a whole number of sectors must be erased at a time.
printf("\nErasing target region...\n");
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
printf("Done. Read back target region:\n");
print_buf(flash_target_contents, FLASH_PAGE_SIZE);
printf("\nProgramming target region...\n");
flash_range_program(FLASH_TARGET_OFFSET, random_data, FLASH_PAGE_SIZE);
printf("Done. Read back target region:\n");
print_buf(flash_target_contents, FLASH_PAGE_SIZE);
bool mismatch = false;
for (int i = 0; i < FLASH_PAGE_SIZE; ++i) {
if (random_data[i] != flash_target_contents[i])
mismatch = true;
}
if (mismatch)
printf("Programming failed!\n");
else
printf("Programming successful!\n");
}

View File

@ -1,14 +0,0 @@
add_executable(flash_ssi_dma
flash_ssi_dma.c
)
target_link_libraries(flash_ssi_dma
pico_stdlib
hardware_dma
)
# create map/bin/hex file etc.
pico_add_extra_outputs(flash_ssi_dma)
# add url via pico_set_program_url
example_auto_set_url(flash_ssi_dma)

View File

@ -1,90 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/time.h"
#include "hardware/dma.h"
#include "hardware/structs/ssi.h"
// This example DMAs 16kB of data from the start of flash to SRAM, and
// measures the transfer speed.
//
// The SSI (flash interface) inside the XIP block has DREQ logic, so we can
// DMA directly from its FIFOs. Unlike the XIP stream hardware (see
// flash_xip_stream.c) this can *not* be done whilst code is running from
// flash, without careful footwork like we do here. The tradeoff is that it's
// ~2.5x as fast in QSPI mode, ~2x as fast in SPI mode.
void __no_inline_not_in_flash_func(flash_bulk_read)(uint32_t *rxbuf, uint32_t flash_offs, size_t len,
uint dma_chan) {
// SSI must be disabled to set transfer size. If software is executing
// from flash right now then it's about to have a bad time
ssi_hw->ssienr = 0;
ssi_hw->ctrlr1 = len - 1; // NDF, number of data frames
ssi_hw->dmacr = SSI_DMACR_TDMAE_BITS | SSI_DMACR_RDMAE_BITS;
ssi_hw->ssienr = 1;
// Other than NDF, the SSI configuration used for XIP is suitable for a bulk read too.
// Configure and start the DMA. Note we are avoiding the dma_*() functions
// as we can't guarantee they'll be inlined
dma_hw->ch[dma_chan].read_addr = (uint32_t) &ssi_hw->dr0;
dma_hw->ch[dma_chan].write_addr = (uint32_t) rxbuf;
dma_hw->ch[dma_chan].transfer_count = len;
// Must enable DMA byteswap because non-XIP 32-bit flash transfers are
// big-endian on SSI (we added a hardware tweak to make XIP sensible)
dma_hw->ch[dma_chan].ctrl_trig =
DMA_CH0_CTRL_TRIG_BSWAP_BITS |
DREQ_XIP_SSIRX << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB |
dma_chan << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB |
DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS |
DMA_CH0_CTRL_TRIG_DATA_SIZE_VALUE_SIZE_WORD << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB |
DMA_CH0_CTRL_TRIG_EN_BITS;
// Now DMA is waiting, kick off the SSI transfer (mode continuation bits in LSBs)
ssi_hw->dr0 = (flash_offs << 8u) | 0xa0u;
// Wait for DMA finish
while (dma_hw->ch[dma_chan].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS);
// Reconfigure SSI before we jump back into flash!
ssi_hw->ssienr = 0;
ssi_hw->ctrlr1 = 0; // Single 32-bit data frame per transfer
ssi_hw->dmacr = 0;
ssi_hw->ssienr = 1;
}
#define DATA_SIZE_WORDS 4096
uint32_t rxdata[DATA_SIZE_WORDS];
uint32_t *expect = (uint32_t *) XIP_NOCACHE_NOALLOC_BASE;
int main() {
stdio_init_all();
memset(rxdata, 0, DATA_SIZE_WORDS * sizeof(uint32_t));
printf("Starting DMA\n");
uint32_t start_time = time_us_32();
flash_bulk_read(rxdata, 0, DATA_SIZE_WORDS, 0);
uint32_t finish_time = time_us_32();
printf("DMA finished\n");
float elapsed_time_s = 1e-6f * (finish_time - start_time);
printf("Transfer speed: %.3f MB/s\n", (sizeof(uint32_t) * DATA_SIZE_WORDS / 1e6f) / elapsed_time_s);
bool mismatch = false;
for (int i = 0; i < DATA_SIZE_WORDS; ++i) {
if (rxdata[i] != expect[i]) {
printf("Mismatch at %d: expected %08x, got %08x\n", i, expect[i], rxdata[i]);
mismatch = true;
break;
}
}
if (!mismatch)
printf("Data check ok\n");
}

View File

@ -1,14 +0,0 @@
add_executable(flash_xip_stream
flash_xip_stream.c
)
target_link_libraries(flash_xip_stream
pico_stdlib
hardware_dma
)
# create map/bin/hex file etc.
pico_add_extra_outputs(flash_xip_stream)
# add url via pico_set_program_url
example_auto_set_url(flash_xip_stream)

View File

@ -1,88 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/regs/addressmap.h"
#include "hardware/structs/xip_ctrl.h"
#include "random_test_data.h"
// The XIP has some internal hardware that can stream a linear access sequence
// to a DMAable FIFO, while the system is still doing random accesses on flash
// code + data.
uint32_t buf[count_of(random_test_data)];
int main() {
stdio_init_all();
for (int i = 0; i < count_of(random_test_data); ++i)
buf[i] = 0;
// This example won't work with PICO_NO_FLASH builds. Note that XIP stream
// can be made to work in these cases, if you enable some XIP mode first
// (e.g. via calling flash_enter_cmd_xip() in ROM). However, you will get
// much better performance by DMAing directly from the SSI's FIFOs, as in
// this way you can clock data continuously on the QSPI bus, rather than a
// series of short transfers.
if ((uint32_t) &random_test_data[0] >= SRAM_BASE) {
printf("You need to run this example from flash!\n");
exit(-1);
}
// Transfer started by writing nonzero value to stream_ctr. stream_ctr
// will count down as the transfer progresses. Can terminate early by
// writing 0 to stream_ctr.
// It's a good idea to drain the FIFO first!
printf("Starting stream from %p\n", random_test_data);
/// \tag::start_stream[]
while (!(xip_ctrl_hw->stat & XIP_STAT_FIFO_EMPTY))
(void) xip_ctrl_hw->stream_fifo;
xip_ctrl_hw->stream_addr = (uint32_t) &random_test_data[0];
xip_ctrl_hw->stream_ctr = count_of(random_test_data);
/// \end::start_stream[]
// Start DMA transfer from XIP stream FIFO to our buffer in memory. Use
// the auxiliary bus slave for the DMA<-FIFO accesses, to avoid stalling
// the DMA against general XIP traffic. Doesn't really matter for this
// example, but it can have a huge effect on DMA throughput.
printf("Starting DMA\n");
/// \tag::start_dma[]
const uint dma_chan = 0;
dma_channel_config cfg = dma_channel_get_default_config(dma_chan);
channel_config_set_read_increment(&cfg, false);
channel_config_set_write_increment(&cfg, true);
channel_config_set_dreq(&cfg, DREQ_XIP_STREAM);
dma_channel_configure(
dma_chan,
&cfg,
(void *) buf, // Write addr
(const void *) XIP_AUX_BASE, // Read addr
count_of(random_test_data), // Transfer count
true // Start immediately!
);
/// \end::start_dma[]
dma_channel_wait_for_finish_blocking(dma_chan);
printf("DMA complete\n");
bool mismatch = false;
for (int i = 0; i < count_of(random_test_data); ++i) {
if (random_test_data[i] != buf[i]) {
printf("Data mismatch: %08x (actual) != %08x (expected)\n", buf[i], random_test_data[i]);
mismatch = true;
break;
}
printf("%08x%c", buf[i], i % 8 == 7 ? '\n' : ' ');
}
if (!mismatch)
printf("Data check OK\n");
}

View File

@ -1,160 +0,0 @@
const uint32_t random_test_data[] = {
0x76654e22, 0x47207265, 0x616e6e6f,
0x76694720, 0x6f592065, 0x70552075,
0x570a0a22, 0x65722765, 0x206f6e20,
0x61727473, 0x7265676e, 0x6f742073,
0x766f6c20, 0x6f590a65, 0x6e6b2075,
0x7420776f, 0x72206568, 0x73656c75,
0x646e6120, 0x206f7320, 0x49206f64,
0x6620410a, 0x206c6c75, 0x6d6d6f63,
0x656d7469, 0x7327746e, 0x61687720,
0x27492074, 0x6874206d, 0x696b6e69,
0x6f20676e, 0x6f590a66, 0x6f772075,
0x6e646c75, 0x67207427, 0x74207465,
0x20736968, 0x6d6f7266, 0x796e6120,
0x68746f20, 0x67207265, 0x0a0a7975,
0x756a2049, 0x77207473, 0x616e6e61,
0x6c657420, 0x6f79206c, 0x6f682075,
0x27492077, 0x6566206d, 0x6e696c65,
0x6f470a67, 0x20617474, 0x656b616d,
0x756f7920, 0x646e7520, 0x74737265,
0x0a646e61, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x76696720, 0x6f792065,
0x70752075, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x74656c20, 0x756f7920,
0x776f6420, 0x654e0a6e, 0x20726576,
0x6e6e6f67, 0x75722061, 0x7261206e,
0x646e756f, 0x646e6120, 0x73656420,
0x20747265, 0x0a756f79, 0x6576654e,
0x6f672072, 0x20616e6e, 0x656b616d,
0x756f7920, 0x79726320, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x79617320,
0x6f6f6720, 0x65796264, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x6c657420,
0x2061206c, 0x2065696c, 0x20646e61,
0x74727568, 0x756f7920, 0x65570a0a,
0x20657627, 0x776f6e6b, 0x6165206e,
0x6f206863, 0x72656874, 0x726f6620,
0x206f7320, 0x676e6f6c, 0x756f590a,
0x65682072, 0x27747261, 0x65622073,
0x61206e65, 0x6e696863, 0x62202c67,
0x590a7475, 0x7227756f, 0x6f742065,
0x6873206f, 0x6f742079, 0x79617320,
0x0a746920, 0x69736e49, 0x202c6564,
0x62206577, 0x2068746f, 0x776f6e6b,
0x61687720, 0x20732774, 0x6e656562,
0x696f6720, 0x6f20676e, 0x65570a6e,
0x6f6e6b20, 0x68742077, 0x61672065,
0x6120656d, 0x7720646e, 0x65722765,
0x6e6f6720, 0x7020616e, 0x2079616c,
0x0a0a7469, 0x20646e41, 0x79206669,
0x6120756f, 0x6d206b73, 0x6f682065,
0x27492077, 0x6566206d, 0x6e696c65,
0x6f440a67, 0x2074276e, 0x6c6c6574,
0x20656d20, 0x27756f79, 0x74206572,
0x62206f6f, 0x646e696c, 0x206f7420,
0x0a656573, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x76696720, 0x6f792065,
0x70752075, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x74656c20, 0x756f7920,
0x776f6420, 0x654e0a6e, 0x20726576,
0x6e6e6f67, 0x75722061, 0x7261206e,
0x646e756f, 0x646e6120, 0x73656420,
0x20747265, 0x0a756f79, 0x6576654e,
0x6f672072, 0x20616e6e, 0x656b616d,
0x756f7920, 0x79726320, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x79617320,
0x6f6f6720, 0x65796264, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x6c657420,
0x2061206c, 0x2065696c, 0x20646e61,
0x74727568, 0x756f7920, 0x654e0a0a,
0x20726576, 0x6e6e6f67, 0x69672061,
0x79206576, 0x7520756f, 0x654e0a70,
0x20726576, 0x6e6e6f67, 0x656c2061,
0x6f792074, 0x6f642075, 0x4e0a6e77,
0x72657665, 0x6e6f6720, 0x7220616e,
0x61206e75, 0x6e756f72, 0x6e612064,
0x65642064, 0x74726573, 0x756f7920,
0x76654e0a, 0x67207265, 0x616e6e6f,
0x6b616d20, 0x6f792065, 0x72632075,
0x654e0a79, 0x20726576, 0x6e6e6f67,
0x61732061, 0x6f672079, 0x7962646f,
0x654e0a65, 0x20726576, 0x6e6e6f67,
0x65742061, 0x61206c6c, 0x65696c20,
0x646e6120, 0x72756820, 0x6f792074,
0x280a0a75, 0x2c686f4f, 0x76696720,
0x6f792065, 0x70752075, 0x4f280a29,
0x202c686f, 0x65766967, 0x756f7920,
0x29707520, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x76696720, 0x6e202c65,
0x72657665, 0x6e6f6720, 0x6720616e,
0x0a657669, 0x76694728, 0x6f792065,
0x70752075, 0x654e0a29, 0x20726576,
0x6e6e6f67, 0x69672061, 0x202c6576,
0x6576656e, 0x6f672072, 0x20616e6e,
0x65766967, 0x6947280a, 0x79206576,
0x7520756f, 0x0a0a2970, 0x76276557,
0x6e6b2065, 0x206e776f, 0x68636165,
0x68746f20, 0x66207265, 0x7320726f,
0x6f6c206f, 0x590a676e, 0x2072756f,
0x72616568, 0x20732774, 0x6e656562,
0x68636120, 0x2c676e69, 0x74756220,
0x756f590a, 0x20657227, 0x206f6f74,
0x20796873, 0x73206f74, 0x69207961,
0x6e490a74, 0x65646973, 0x6577202c,
0x746f6220, 0x6e6b2068, 0x7720776f,
0x27746168, 0x65622073, 0x67206e65,
0x676e696f, 0x0a6e6f20, 0x6b206557,
0x20776f6e, 0x20656874, 0x656d6167,
0x646e6120, 0x27657720, 0x67206572,
0x616e6e6f, 0x616c7020, 0x74692079,
0x20490a0a, 0x7473756a, 0x6e617720,
0x7420616e, 0x206c6c65, 0x20756f79,
0x20776f68, 0x206d2749, 0x6c656566,
0x0a676e69, 0x74746f47, 0x616d2061,
0x7920656b, 0x7520756f, 0x7265646e,
0x6e617473, 0x4e0a0a64, 0x72657665,
0x6e6f6720, 0x6720616e, 0x20657669,
0x20756f79, 0x4e0a7075, 0x72657665,
0x6e6f6720, 0x6c20616e, 0x79207465,
0x6420756f, 0x0a6e776f, 0x6576654e,
0x6f672072, 0x20616e6e, 0x206e7572,
0x756f7261, 0x6120646e, 0x6420646e,
0x72657365, 0x6f792074, 0x654e0a75,
0x20726576, 0x6e6e6f67, 0x616d2061,
0x7920656b, 0x6320756f, 0x4e0a7972,
0x72657665, 0x6e6f6720, 0x7320616e,
0x67207961, 0x62646f6f, 0x4e0a6579,
0x72657665, 0x6e6f6720, 0x7420616e,
0x206c6c65, 0x696c2061, 0x6e612065,
0x75682064, 0x79207472, 0x0a0a756f,
0x6576654e, 0x6f672072, 0x20616e6e,
0x65766967, 0x756f7920, 0x0a707520,
0x6576654e, 0x6f672072, 0x20616e6e,
0x2074656c, 0x20756f79, 0x6e776f64,
0x76654e0a, 0x67207265, 0x616e6e6f,
0x6e757220, 0x6f726120, 0x20646e75,
0x20646e61, 0x65736564, 0x79207472,
0x4e0a756f, 0x72657665, 0x6e6f6720,
0x6d20616e, 0x20656b61, 0x20756f79,
0x0a797263, 0x6576654e, 0x6f672072,
0x20616e6e, 0x20796173, 0x646f6f67,
0x0a657962, 0x6576654e, 0x6f672072,
0x20616e6e, 0x6c6c6574, 0x6c206120,
0x61206569, 0x6820646e, 0x20747275,
0x0a756f79, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x76696720, 0x6f792065,
0x70752075, 0x76654e0a, 0x67207265,
0x616e6e6f, 0x74656c20, 0x756f7920,
0x776f6420, 0x654e0a6e, 0x20726576,
0x6e6e6f67, 0x75722061, 0x7261206e,
0x646e756f, 0x646e6120, 0x73656420,
0x20747265, 0x0a756f79, 0x6576654e,
0x6f672072, 0x20616e6e, 0x656b616d,
0x756f7920, 0x79726320, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x79617320,
0x6f6f6720, 0x65796264, 0x76654e0a,
0x67207265, 0x616e6e6f, 0x6c657420,
0x2061206c, 0x2065696c, 0x20646e61
};

View File

@ -1,5 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(dht_sensor)
add_subdirectory(hello_7segment)
add_subdirectory(hello_gpio_irq)
endif ()

View File

@ -1,11 +0,0 @@
add_executable(dht
dht.c
)
target_link_libraries(dht pico_stdlib)
pico_add_extra_outputs(dht)
# add url via pico_set_program_url
example_auto_set_url(dht)

View File

@ -1,58 +0,0 @@
= DHT-11, DHT-22, and AM2302 Sensors
:xrefstyle: short
The DHT sensors are fairly well known hobbyist sensors for measuring relative humidity and temperature using a capacitive humidity sensor, and a thermistor. While they are slow, one reading every ~2 seconds, they are reliable and good for basic data logging. Communication is based on a custom protocol which uses a single wire for data.
[NOTE]
======
The DHT-11 and DHT-22 sensors are the most common. They use the same protocol but have different characteristics, the DHT-22 has better accuracy, and has a larger sensor range than the DHT-11. The sensor is available from a number of retailers.
======
== Wiring information
See <<dht-wiring-diagram>> for wiring instructions.
[[dht-wiring-diagram]]
[pdfwidth=75%]
.Wiring the DHT-22 temperature sensor to Raspberry Pi Pico, and connecting Pico's UART0 to the Raspberry Pi 4.
image::pi-and-pico-uart-and-dht-sensor.png[]
NOTE: One of the pins (pin 3) on the DHT sensor will not be connected, it is not used.
You will want to place a 10 kΩ resistor between VCC and the data pin, to act as a medium-strength pull up on the data line.
Connecting UART0 of Pico to Raspberry Pi as in <<dht-wiring-diagram>> and you should see something similar to <<dht-serial-output-diagram>> in `minicom` when connected to `/dev/serial0` on the Raspberry Pi.
[[dht-serial-output-diagram]]
[pdfwidth=75%]
.Serial output over Pico's UART0 in a terminal window.
image::serial-output.png[]
Connect to `/dev/serial0` by typing,
----
$ minicom -b 115200 -o -D /dev/serial0
----
at the command line.
== List of Files
A list of files with descriptions of their function;
CMakeLists.txt:: Make file to incorporate the example in to the examples build tree.
dht.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[dht-22-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| 10 kΩ resistor | 1 | generic part
| M/M Jumper wires | 4 | generic part
| DHT-22 sensor | 1 | generic part
|===

View File

@ -1,92 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
**/
#include <stdio.h>
#include <math.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#ifdef PICO_DEFAULT_LED_PIN
#define LED_PIN PICO_DEFAULT_LED_PIN
#endif
const uint DHT_PIN = 15;
const uint MAX_TIMINGS = 85;
typedef struct {
float humidity;
float temp_celsius;
} dht_reading;
void read_from_dht(dht_reading *result);
int main() {
stdio_init_all();
gpio_init(DHT_PIN);
#ifdef LED_PIN
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
#endif
while (1) {
dht_reading reading;
read_from_dht(&reading);
float fahrenheit = (reading.temp_celsius * 9 / 5) + 32;
printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n",
reading.humidity, reading.temp_celsius, fahrenheit);
sleep_ms(2000);
}
}
void read_from_dht(dht_reading *result) {
int data[5] = {0, 0, 0, 0, 0};
uint last = 1;
uint j = 0;
gpio_set_dir(DHT_PIN, GPIO_OUT);
gpio_put(DHT_PIN, 0);
sleep_ms(20);
gpio_set_dir(DHT_PIN, GPIO_IN);
#ifdef LED_PIN
gpio_put(LED_PIN, 1);
#endif
for (uint i = 0; i < MAX_TIMINGS; i++) {
uint count = 0;
while (gpio_get(DHT_PIN) == last) {
count++;
sleep_us(1);
if (count == 255) break;
}
last = gpio_get(DHT_PIN);
if (count == 255) break;
if ((i >= 4) && (i % 2 == 0)) {
data[j / 8] <<= 1;
if (count > 16) data[j / 8] |= 1;
j++;
}
}
#ifdef LED_PIN
gpio_put(LED_PIN, 0);
#endif
if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
result->humidity = (float) ((data[0] << 8) + data[1]) / 10;
if (result->humidity > 100) {
result->humidity = data[0];
}
result->temp_celsius = (float) (((data[2] & 0x7F) << 8) + data[3]) / 10;
if (result->temp_celsius > 125) {
result->temp_celsius = data[2];
}
if (data[2] & 0x80) {
result->temp_celsius = -result->temp_celsius;
}
} else {
printf("Bad data\n");
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 KiB

View File

@ -1,12 +0,0 @@
add_executable(hello_7segment
hello_7segment.c
)
# pull in common dependencies
target_link_libraries(hello_7segment pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_7segment)
# add url via pico_set_program_url
example_auto_set_url(hello_7segment)

View File

@ -1,48 +0,0 @@
= Attaching a 7 segment LED via GPIO
This example code shows how to interface the Raspberry Pi Pico to a generic 7 segment LED device. It uses the LED to count from 0 to 9 and then repeat. If the button is pressed, then the numbers will count down instead of up.
== Wiring information
Our 7 Segment display has pins as follows.
----
--A--
F B
--G--
E C
--D--
----
By default we are allocating GPIO 2 to segment A, 3 to B etc.
So, connect GPIO 2 to pin A on the 7 segment LED display and so on. You will need the appropriate resistors (68 ohm should be fine) for each segment.
The LED device used here is common anode, so the anode pin is connected to the 3.3v supply, and the GPIOs need to pull low (to ground) to complete the circuit.
The pull direction of the GPIOs is specified in the code itself.
Connect the switch to connect on pressing. One side should be connected to ground, the other to GPIO 9.
[[hello_7segment_wiring]]
[pdfwidth=75%]
.Wiring Diagram for 7 segment LED.
image::hello_7segment_bb.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
hello_7segment.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[hello_7segment-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| 7 segment LED module | 1 | generic part
| 68 ohm resistor | 7 | generic part
| DIL push to make switch | 1 | generic switch
| M/M Jumper wires | 10 | generic part
|===

View File

@ -1,95 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
/*
Our 7 Segment display has pins as follows:
--A--
F B
--G--
E C
--D--
By default we are allocating GPIO 2 to segment A, 3 to B etc.
So, connect GPIO 2 to pin A on the 7 segment LED display etc. Don't forget
the appropriate resistors, best to use one for each segment!
Connect button so that pressing the switch connects the GPIO 9 (default) to
ground (pull down)
*/
#define FIRST_GPIO 2
#define BUTTON_GPIO (FIRST_GPIO+7)
// This array converts a number 0-9 to a bit pattern to send to the GPIOs
int bits[10] = {
0x3f, // 0
0x06, // 1
0x5b, // 2
0x4f, // 3
0x66, // 4
0x6d, // 5
0x7d, // 6
0x07, // 7
0x7f, // 8
0x67 // 9
};
/// \tag::hello_gpio[]
int main() {
stdio_init_all();
printf("Hello, 7segment - press button to count down!\n");
// We could use gpio_set_dir_out_masked() here
for (int gpio = FIRST_GPIO; gpio < FIRST_GPIO + 7; gpio++) {
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
// Our bitmap above has a bit set where we need an LED on, BUT, we are pulling low to light
// so invert our output
gpio_set_outover(gpio, GPIO_OVERRIDE_INVERT);
}
gpio_init(BUTTON_GPIO);
gpio_set_dir(BUTTON_GPIO, GPIO_IN);
// We are using the button to pull down to 0v when pressed, so ensure that when
// unpressed, it uses internal pull ups. Otherwise when unpressed, the input will
// be floating.
gpio_pull_up(BUTTON_GPIO);
int val = 0;
while (true) {
// Count upwards or downwards depending on button input
// We are pulling down on switch active, so invert the get to make
// a press count downwards
if (!gpio_get(BUTTON_GPIO)) {
if (val == 9) {
val = 0;
} else {
val++;
}
} else if (val == 0) {
val = 9;
} else {
val--;
}
// We are starting with GPIO 2, our bitmap starts at bit 0 so shift to start at 2.
int32_t mask = bits[val] << FIRST_GPIO;
// Set all our GPIOs in one go!
// If something else is using GPIO, we might want to use gpio_put_masked()
gpio_set_mask(mask);
sleep_ms(250);
gpio_clr_mask(mask);
}
return 0;
}
/// \end::hello_gpio[]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

View File

@ -1,12 +0,0 @@
add_executable(hello_gpio_irq
hello_gpio_irq.c
)
# pull in common dependencies
target_link_libraries(hello_gpio_irq pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_gpio_irq)
# add url via pico_set_program_url
example_auto_set_url(hello_gpio_irq)

View File

@ -1,61 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
static char event_str[128];
void gpio_event_string(char *buf, uint32_t events);
void gpio_callback(uint gpio, uint32_t events) {
// Put the GPIO event(s) that just happened into event_str
// so we can print it
gpio_event_string(event_str, events);
printf("GPIO %d %s\n", gpio, event_str);
}
int main() {
stdio_init_all();
printf("Hello GPIO IRQ\n");
gpio_set_irq_enabled_with_callback(2, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
// Wait forever
while (1);
return 0;
}
static const char *gpio_irq_str[] = {
"LEVEL_LOW", // 0x1
"LEVEL_HIGH", // 0x2
"EDGE_FALL", // 0x4
"EDGE_RISE" // 0x8
};
void gpio_event_string(char *buf, uint32_t events) {
for (uint i = 0; i < 4; i++) {
uint mask = (1 << i);
if (events & mask) {
// Copy this event string into the user string
const char *event_str = gpio_irq_str[i];
while (*event_str != '\0') {
*buf++ = *event_str++;
}
events &= ~mask;
// If more events add ", "
if (events) {
*buf++ = ',';
*buf++ = ' ';
}
}
}
*buf++ = '\0';
}

View File

@ -1,2 +0,0 @@
add_subdirectory(serial)
add_subdirectory(usb)

View File

@ -1,12 +0,0 @@
add_executable(hello_serial
hello_serial.c
)
# pull in common dependencies
target_link_libraries(hello_serial pico_stdlib)
# create map/bin/hex/uf2 file etc.
pico_add_extra_outputs(hello_serial)
# add url via pico_set_program_url
example_auto_set_url(hello_serial)

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
int main() {
stdio_init_all();
while (true) {
printf("Hello, world!\n");
sleep_ms(1000);
}
return 0;
}

View File

@ -1,20 +0,0 @@
if (TARGET tinyusb_device)
add_executable(hello_usb
hello_usb.c
)
# pull in common dependencies
target_link_libraries(hello_usb pico_stdlib)
# enable usb output, disable uart output
pico_enable_stdio_usb(hello_usb 1)
pico_enable_stdio_uart(hello_usb 0)
# create map/bin/hex/uf2 file etc.
pico_add_extra_outputs(hello_usb)
# add url via pico_set_program_url
example_auto_set_url(hello_usb)
elseif(PICO_ON_DEVICE)
message(WARNING "not building hello_usb because TinyUSB submodule is not initialized in the SDK")
endif()

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
int main() {
stdio_init_all();
while (true) {
printf("Hello, world!\n");
sleep_ms(1000);
}
return 0;
}

View File

@ -1,13 +0,0 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(bmp280_i2c)
add_subdirectory(bus_scan)
add_subdirectory(lcd_1602_i2c)
add_subdirectory(lis3dh_i2c)
add_subdirectory(mcp9808_i2c)
add_subdirectory(mma8451_i2c)
add_subdirectory(mpl3115a2_i2c)
add_subdirectory(mpu6050_i2c)
add_subdirectory(oled_i2c)
add_subdirectory(pa1010d_i2c)
add_subdirectory(pcf8523_i2c)
endif ()

View File

@ -1,12 +0,0 @@
add_executable(bmp280_i2c
bmp280_i2c.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(bmp280_i2c pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(bmp280_i2c)
# add url via pico_set_program_url
example_auto_set_url(bmp280_i2c)

View File

@ -1,41 +0,0 @@
= Attaching a BMP280 temp/pressure sensor via I2C
This example code shows how to interface the Raspberry Pi Pico with the popular BMP280 temperature and air pressure sensor manufactured by Bosch. A similar variant, the BME280, exists that can also measure humidity. There is another example that uses the BME280 device but talks to it via SPI as opposed to I2C.
The code reads data from the sensor's registers every 500 milliseconds and prints it via the onboard UART. This example operates the BMP280 in _normal_ mode, meaning that the device continuously cycles between a measurement period and a standby period at a regular interval we can set. This has the advantage that subsequent reads do not require configuration register writes and is the recommended mode of operation to filter out short-term disturbances.
[TIP]
======
The BMP280 is highly configurable with 3 modes of operation, various oversampling levels, and 5 filter settings. Find the datasheet online (https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf) to explore all of its capabilities beyond the simple example given here.
======
== Wiring information
Wiring up the device requires 4 jumpers, to connect VCC (3.3v), GND, SDA and SCL. The example here uses the default I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the 3.3V pin from the Pico.
WARNING: The BMP280 has a maximum supply voltage rating of 3.6V. Most breakout boards have voltage regulators that will allow a range of input voltages of 2-6V, but make sure to check beforehand.
[[bmp280_i2c_wiring]]
[pdfwidth=75%]
.Wiring Diagram for BMP280 sensor via I2C.
image::bmp280_i2c_bb.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example into the examples build tree.
bmp280_i2c.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[bmp280_i2c-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| BMP280-based breakout board | 1 | https://shop.pimoroni.com/products/bmp280-breakout-temperature-pressure-altitude-sensor[from Pimoroni]
| M/M Jumper wires | 4 | generic part
|===

View File

@ -1,254 +0,0 @@
/**
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
**/
#include <stdio.h>
#include "hardware/i2c.h"
#include "pico/binary_info.h"
#include "pico/stdlib.h"
/* Example code to talk to a BMP280 temperature and pressure sensor
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
GPIO (and therefore I2C) cannot be used at 5v.
You will need to use a level shifter on the I2C lines if you want to run the
board at 5v.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO PICO_DEFAULT_I2C_SDA_PIN (on Pico this is GP4 (pin 6)) -> SDA on BMP280
board
GPIO PICO_DEFAULT_I2C_SCK_PIN (on Pico this is GP5 (pin 7)) -> SCL on
BMP280 board
3.3v (pin 36) -> VCC on BMP280 board
GND (pin 38) -> GND on BMP280 board
*/
// device has default bus address of 0x76
#define ADDR _u(0x76)
// hardware registers
#define REG_CONFIG _u(0xF5)
#define REG_CTRL_MEAS _u(0xF4)
#define REG_RESET _u(0xE0)
#define REG_TEMP_XLSB _u(0xFC)
#define REG_TEMP_LSB _u(0xFB)
#define REG_TEMP_MSB _u(0xFA)
#define REG_PRESSURE_XLSB _u(0xF9)
#define REG_PRESSURE_LSB _u(0xF8)
#define REG_PRESSURE_MSB _u(0xF7)
// calibration registers
#define REG_DIG_T1_LSB _u(0x88)
#define REG_DIG_T1_MSB _u(0x89)
#define REG_DIG_T2_LSB _u(0x8A)
#define REG_DIG_T2_MSB _u(0x8B)
#define REG_DIG_T3_LSB _u(0x8C)
#define REG_DIG_T3_MSB _u(0x8D)
#define REG_DIG_P1_LSB _u(0x8E)
#define REG_DIG_P1_MSB _u(0x8F)
#define REG_DIG_P2_LSB _u(0x90)
#define REG_DIG_P2_MSB _u(0x91)
#define REG_DIG_P3_LSB _u(0x92)
#define REG_DIG_P3_MSB _u(0x93)
#define REG_DIG_P4_LSB _u(0x94)
#define REG_DIG_P4_MSB _u(0x95)
#define REG_DIG_P5_LSB _u(0x96)
#define REG_DIG_P5_MSB _u(0x97)
#define REG_DIG_P6_LSB _u(0x98)
#define REG_DIG_P6_MSB _u(0x99)
#define REG_DIG_P7_LSB _u(0x9A)
#define REG_DIG_P7_MSB _u(0x9B)
#define REG_DIG_P8_LSB _u(0x9C)
#define REG_DIG_P8_MSB _u(0x9D)
#define REG_DIG_P9_LSB _u(0x9E)
#define REG_DIG_P9_MSB _u(0x9F)
// number of calibration registers to be read
#define NUM_CALIB_PARAMS 24
struct bmp280_calib_param {
// temperature params
uint16_t dig_t1;
int16_t dig_t2;
int16_t dig_t3;
// pressure params
uint16_t dig_p1;
int16_t dig_p2;
int16_t dig_p3;
int16_t dig_p4;
int16_t dig_p5;
int16_t dig_p6;
int16_t dig_p7;
int16_t dig_p8;
int16_t dig_p9;
};
#ifdef i2c_default
void bmp280_init() {
// use the "handheld device dynamic" optimal setting (see datasheet)
uint8_t buf[2];
// 500ms sampling time, x16 filter
const uint8_t reg_config_val = ((0x04 << 5) | (0x05 << 2)) & 0xFC;
// send register number followed by its corresponding value
buf[0] = REG_CONFIG;
buf[1] = reg_config_val;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
// osrs_t x1, osrs_p x4, normal mode operation
const uint8_t reg_ctrl_meas_val = (0x01 << 5) | (0x03 << 2) | (0x03);
buf[0] = REG_CTRL_MEAS;
buf[1] = reg_ctrl_meas_val;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
}
void bmp280_read_raw(int32_t* temp, int32_t* pressure) {
// BMP280 data registers are auto-incrementing and we have 3 temperature and
// pressure registers each, so we start at 0xF7 and read 6 bytes to 0xFC
// note: normal mode does not require further ctrl_meas and config register writes
uint8_t buf[6];
uint8_t reg = REG_PRESSURE_MSB;
i2c_write_blocking(i2c_default, ADDR, &reg, 1, true); // true to keep master control of bus
i2c_read_blocking(i2c_default, ADDR, buf, 6, false); // false - finished with bus
// store the 20 bit read in a 32 bit signed integer for conversion
*pressure = (buf[0] << 12) | (buf[1] << 4) | (buf[2] >> 4);
*temp = (buf[3] << 12) | (buf[4] << 4) | (buf[5] >> 4);
}
void bmp280_reset() {
// reset the device with the power-on-reset procedure
uint8_t buf[2] = { REG_RESET, 0xB6 };
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
}
// intermediate function that calculates the fine resolution temperature
// used for both pressure and temperature conversions
int32_t bmp280_convert(int32_t temp, struct bmp280_calib_param* params) {
// use the 32-bit fixed point compensation implementation given in the
// datasheet
int32_t var1, var2;
var1 = ((((temp >> 3) - ((int32_t)params->dig_t1 << 1))) * ((int32_t)params->dig_t2)) >> 11;
var2 = (((((temp >> 4) - ((int32_t)params->dig_t1)) * ((temp >> 4) - ((int32_t)params->dig_t1))) >> 12) * ((int32_t)params->dig_t3)) >> 14;
return var1 + var2;
}
int32_t bmp280_convert_temp(int32_t temp, struct bmp280_calib_param* params) {
// uses the BMP280 calibration parameters to compensate the temperature value read from its registers
int32_t t_fine = bmp280_convert(temp, params);
return (t_fine * 5 + 128) >> 8;
}
int32_t bmp280_convert_pressure(int32_t pressure, int32_t temp, struct bmp280_calib_param* params) {
// uses the BMP280 calibration parameters to compensate the pressure value read from its registers
int32_t t_fine = bmp280_convert(temp, params);
int32_t var1, var2;
uint32_t converted = 0.0;
var1 = (((int32_t)t_fine) >> 1) - (int32_t)64000;
var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)params->dig_p6);
var2 += ((var1 * ((int32_t)params->dig_p5)) << 1);
var2 = (var2 >> 2) + (((int32_t)params->dig_p4) << 16);
var1 = (((params->dig_p3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + ((((int32_t)params->dig_p2) * var1) >> 1)) >> 18;
var1 = ((((32768 + var1)) * ((int32_t)params->dig_p1)) >> 15);
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
converted = (((uint32_t)(((int32_t)1048576) - pressure) - (var2 >> 12))) * 3125;
if (converted < 0x80000000) {
converted = (converted << 1) / ((uint32_t)var1);
} else {
converted = (converted / (uint32_t)var1) * 2;
}
var1 = (((int32_t)params->dig_p9) * ((int32_t)(((converted >> 3) * (converted >> 3)) >> 13))) >> 12;
var2 = (((int32_t)(converted >> 2)) * ((int32_t)params->dig_p8)) >> 13;
converted = (uint32_t)((int32_t)converted + ((var1 + var2 + params->dig_p7) >> 4));
return converted;
}
void bmp280_get_calib_params(struct bmp280_calib_param* params) {
// raw temp and pressure values need to be calibrated according to
// parameters generated during the manufacturing of the sensor
// there are 3 temperature params, and 9 pressure params, each with a LSB
// and MSB register, so we read from 24 registers
uint8_t buf[NUM_CALIB_PARAMS] = { 0 };
uint8_t reg = REG_DIG_T1_LSB;
i2c_write_blocking(i2c_default, ADDR, &reg, 1, true); // true to keep master control of bus
// read in one go as register addresses auto-increment
i2c_read_blocking(i2c_default, ADDR, buf, NUM_CALIB_PARAMS, false); // false, we're done reading
// store these in a struct for later use
params->dig_t1 = (uint16_t)(buf[1] << 8) | buf[0];
params->dig_t2 = (int16_t)(buf[3] << 8) | buf[2];
params->dig_t3 = (int16_t)(buf[5] << 8) | buf[4];
params->dig_p1 = (uint16_t)(buf[7] << 8) | buf[6];
params->dig_p2 = (int16_t)(buf[9] << 8) | buf[8];
params->dig_p3 = (int16_t)(buf[11] << 8) | buf[10];
params->dig_p4 = (int16_t)(buf[13] << 8) | buf[12];
params->dig_p5 = (int16_t)(buf[15] << 8) | buf[14];
params->dig_p6 = (int16_t)(buf[17] << 8) | buf[16];
params->dig_p7 = (int16_t)(buf[19] << 8) | buf[18];
params->dig_p8 = (int16_t)(buf[21] << 8) | buf[20];
params->dig_p9 = (int16_t)(buf[23] << 8) | buf[22];
}
#endif
int main() {
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c / bmp280_i2c example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
// useful information for picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
bi_decl(bi_program_description("BMP280 I2C example for the Raspberry Pi Pico"));
printf("Hello, BMP280! Reading temperaure and pressure values from sensor...\n");
// I2C is "open drain", pull ups to keep signal high when no data is being sent
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// configure BMP280
bmp280_init();
// retrieve fixed compensation params
struct bmp280_calib_param params;
bmp280_get_calib_params(&params);
int32_t raw_temperature;
int32_t raw_pressure;
sleep_ms(250); // sleep so that data polling and register update don't collide
while (1) {
bmp280_read_raw(&raw_temperature, &raw_pressure);
int32_t temperature = bmp280_convert_temp(raw_temperature, &params);
int32_t pressure = bmp280_convert_pressure(raw_pressure, raw_temperature, &params);
printf("Pressure = %.3f kPa\n", pressure / 1000.f);
printf("Temp. = %.2f C\n", temperature / 100.f);
// poll every 500ms
sleep_ms(500);
}
#endif
return 0;
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View File

@ -1,12 +0,0 @@
add_executable(i2c_bus_scan
bus_scan.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(i2c_bus_scan pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(i2c_bus_scan)
# add url via pico_set_program_url
example_auto_set_url(i2c_bus_scan)

View File

@ -1,77 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Sweep through all 7-bit I2C addresses, to see if any slaves are present on
// the I2C bus. Print out a table that looks like this:
//
// I2C Bus Scan
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
// 0
// 1 @
// 2
// 3 @
// 4
// 5
// 6
// 7
//
// E.g. if slave addresses 0x12 and 0x34 were acknowledged.
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
// I2C reserves some addresses for special purposes. We exclude these from the scan.
// These are any addresses of the form 000 0xxx or 111 1xxx
bool reserved_addr(uint8_t addr) {
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78;
}
int main() {
// Enable UART so we can print status output
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/bus_scan example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
// This example will use I2C0 on the default SDA and SCL pins (GP4, GP5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
printf("\nI2C Bus Scan\n");
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (int addr = 0; addr < (1 << 7); ++addr) {
if (addr % 16 == 0) {
printf("%02x ", addr);
}
// Perform a 1-byte dummy read from the probe address. If a slave
// acknowledges this address, the function returns the number of bytes
// transferred. If the address byte is ignored, the function returns
// -1.
// Skip over any reserved addresses.
int ret;
uint8_t rxdata;
if (reserved_addr(addr))
ret = PICO_ERROR_GENERIC;
else
ret = i2c_read_blocking(i2c_default, addr, &rxdata, 1, false);
printf(ret < 0 ? "." : "@");
printf(addr % 16 == 15 ? "\n" : " ");
}
printf("Done.\n");
return 0;
#endif
}

View File

@ -1,12 +0,0 @@
add_executable(lcd_1602_i2c
lcd_1602_i2c.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(lcd_1602_i2c pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(lcd_1602_i2c)
# add url via pico_set_program_url
example_auto_set_url(lcd_1602_i2c)

View File

@ -1,39 +0,0 @@
= Attaching a 16x2 LCD via I2C
This example code shows how to interface the Raspberry Pi Pico to one of the very common 16x2 LCD character displays. The display will need a 3.3V I2C adapter board as this example uses I2C for communications.
[NOTE]
======
These LCD displays can also be driven directly using GPIO without the use of an adapter board. That is beyond the scope of this example.
======
== Wiring information
Wiring up the device requires 4 jumpers, to connect VCC (3.3v), GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the 3.3V pin.
WARNING: Many displays of this type are 5v. If you wish to use a 5v display you will need to use level shifters on the SDA and SCL lines to convert from the 3.3V used by the RP2040. Whilst a 5v display will just about work at 3.3v, the display will be dim.
[[lcd_1602_i2c_wiring]]
[pdfwidth=75%]
.Wiring Diagram for LCD1602A LCD with I2C bridge.
image::lcd_1602_i2c_bb.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
lcd_1602_i2c.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[lcd_1602_i2c-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| 1602A based LCD panel 3.3v | 1 | generic part
| 1602A to I2C bridge device 3.3v | 1 | generic part
| M/M Jumper wires | 4 | generic part
|===

View File

@ -1,169 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "pico/binary_info.h"
/* Example code to drive a 16x2 LCD panel via a I2C bridge chip (e.g. PCF8574)
NOTE: The panel must be capable of being driven at 3.3v NOT 5v. The Pico
GPIO (and therefor I2C) cannot be used at 5v.
You will need to use a level shifter on the I2C lines if you want to run the
board at 5v.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO 4 (pin 6)-> SDA on LCD bridge board
GPIO 5 (pin 7)-> SCL on LCD bridge board
3.3v (pin 36) -> VCC on LCD bridge board
GND (pin 38) -> GND on LCD bridge board
*/
// commands
const int LCD_CLEARDISPLAY = 0x01;
const int LCD_RETURNHOME = 0x02;
const int LCD_ENTRYMODESET = 0x04;
const int LCD_DISPLAYCONTROL = 0x08;
const int LCD_CURSORSHIFT = 0x10;
const int LCD_FUNCTIONSET = 0x20;
const int LCD_SETCGRAMADDR = 0x40;
const int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
const int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
const int LCD_BLINKON = 0x01;
const int LCD_CURSORON = 0x02;
const int LCD_DISPLAYON = 0x04;
// flags for display and cursor shift
const int LCD_MOVERIGHT = 0x04;
const int LCD_DISPLAYMOVE = 0x08;
// flags for function set
const int LCD_5x10DOTS = 0x04;
const int LCD_2LINE = 0x08;
const int LCD_8BITMODE = 0x10;
// flag for backlight control
const int LCD_BACKLIGHT = 0x08;
const int LCD_ENABLE_BIT = 0x04;
// By default these LCD display drivers are on bus address 0x27
static int addr = 0x27;
// Modes for lcd_send_byte
#define LCD_CHARACTER 1
#define LCD_COMMAND 0
#define MAX_LINES 2
#define MAX_CHARS 16
/* Quick helper function for single byte transfers */
void i2c_write_byte(uint8_t val) {
#ifdef i2c_default
i2c_write_blocking(i2c_default, addr, &val, 1, false);
#endif
}
void lcd_toggle_enable(uint8_t val) {
// Toggle enable pin on LCD display
// We cannot do this too quickly or things don't work
#define DELAY_US 600
sleep_us(DELAY_US);
i2c_write_byte(val | LCD_ENABLE_BIT);
sleep_us(DELAY_US);
i2c_write_byte(val & ~LCD_ENABLE_BIT);
sleep_us(DELAY_US);
}
// The display is sent a byte as two separate nibble transfers
void lcd_send_byte(uint8_t val, int mode) {
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2c_write_byte(high);
lcd_toggle_enable(high);
i2c_write_byte(low);
lcd_toggle_enable(low);
}
void lcd_clear(void) {
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
}
// go to location on LCD
void lcd_set_cursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
lcd_send_byte(val, LCD_COMMAND);
}
static void inline lcd_char(char val) {
lcd_send_byte(val, LCD_CHARACTER);
}
void lcd_string(const char *s) {
while (*s) {
lcd_char(*s++);
}
}
void lcd_init() {
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x02, LCD_COMMAND);
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
lcd_clear();
}
int main() {
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/lcd_1602_i2c example requires a board with I2C pins
#else
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
lcd_init();
static char *message[] =
{
"RP2040 by", "Raspberry Pi",
"A brand new", "microcontroller",
"Twin core M0", "Full C SDK",
"More power in", "your product",
"More beans", "than Heinz!"
};
while (1) {
for (int m = 0; m < sizeof(message) / sizeof(message[0]); m += MAX_LINES) {
for (int line = 0; line < MAX_LINES; line++) {
lcd_set_cursor(line, (MAX_CHARS / 2) - strlen(message[m + line]) / 2);
lcd_string(message[m + line]);
}
sleep_ms(2000);
lcd_clear();
}
}
return 0;
#endif
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

View File

@ -1,12 +0,0 @@
add_executable(lis3dh_i2c
lis3dh_i2c.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(lis3dh_i2c pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(lis3dh_i2c)
# add url via pico_set_program_url
example_auto_set_url(lis3dh_i2c)

View File

@ -1,38 +0,0 @@
= Attaching a LIS3DH Nano Accelerometer via i2c.
This example shows you how to interface the Raspberry Pi Pico to the LIS3DH accelerometer and temperature sensor.
The code reads and displays the acceleration values of the board in the 3 axes and the ambient temperature value. The datasheet for the sensor can be found at https://www.st.com/resource/en/datasheet/cd00274221.pdf. The device is being operated on 'normal mode' and at a frequency of 1.344 kHz (this can be changed by editing the ODR bits of CTRL_REG4). The range of the data is controlled by the FS bit in CTRL_REG4 and is equal to ±2g in this example. The sensitivity depends on the operating mode and data range; exact values can be found on page 10 of the datasheet. In this case, the sensitivity value is 4mg (where g is the value of gravitational acceleration on the surface of Earth). In order to use the auxiliary ADC to read temperature, the we must set the BDU bit to 1 in CTRL_REG4 and the ADC_EN bit to 1 in TEMP_CFG_REG. Temperature is communicated through ADC 3.
[NOTE]
=====
The sensor doesn't have features to eliminate offsets in the data and these will need to be taken into account in the code.
=====
== Wiring information
Wiring up the device requires 4 jumpers, to connect VIN, GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the 3V pin.
[[lis3dh_i2c_wiring]]
[pdfwidth=75%]
.Wiring Diagram for LIS3DH.
image::lis3dh_i2c.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
lis3dh_i2c.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[lis3dh-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| LIS3DH board| 1 | https://www.adafruit.com/product/2809
| M/M Jumper wires | 4 | generic part
|===

View File

@ -1,129 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
/* Example code to talk to a LIS3DH Mini GPS module.
This example reads data from all 3 axes of the accelerometer and uses an auxillary ADC to output temperature values.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is 4 (physical pin 6)) -> SDA on LIS3DH board
GPIO PICO_DEFAULT_I2C_SCK_PIN (On Pico this is 5 (physical pin 7)) -> SCL on LIS3DH board
3.3v (physical pin 36) -> VIN on LIS3DH board
GND (physical pin 38) -> GND on LIS3DH board
*/
// By default this device is on bus address 0x18
const int ADDRESS = 0x18;
const uint8_t CTRL_REG_1 = 0x20;
const uint8_t CTRL_REG_4 = 0x23;
const uint8_t TEMP_CFG_REG = 0xC0;
#ifdef i2c_default
void lis3dh_init() {
uint8_t buf[2];
// Turn normal mode and 1.344kHz data rate on
buf[0] = CTRL_REG_1;
buf[1] = 0x97;
i2c_write_blocking(i2c_default, ADDRESS, buf, 2, false);
// Turn block data update on (for temperature sensing)
buf[0] = CTRL_REG_4;
buf[1] = 0x80;
i2c_write_blocking(i2c_default, ADDRESS, buf, 2, false);
// Turn auxillary ADC on
buf[0] = TEMP_CFG_REG;
buf[1] = 0xC0;
i2c_write_blocking(i2c_default, ADDRESS, buf, 2, false);
}
void lis3dh_calc_value(uint16_t raw_value, float *final_value, bool isAccel) {
// Convert with respect to the value being temperature or acceleration reading
float scaling;
float senstivity = 0.004f; // g per unit
if (isAccel == true) {
scaling = 64 / senstivity;
} else {
scaling = 64;
}
// raw_value is signed
*final_value = (float) ((int16_t) raw_value) / scaling;
}
void lis3dh_read_data(uint8_t reg, float *final_value, bool IsAccel) {
// Read two bytes of data and store in a 16 bit data structure
uint8_t lsb;
uint8_t msb;
uint16_t raw_accel;
i2c_write_blocking(i2c_default, ADDRESS, &reg, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, &lsb, 1, false);
reg |= 0x01;
i2c_write_blocking(i2c_default, ADDRESS, &reg, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, &msb, 1, false);
raw_accel = (msb << 8) | lsb;
lis3dh_calc_value(raw_accel, final_value, IsAccel);
}
#endif
int main() {
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/lis3dh_i2c example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
printf("Hello, LIS3DH! Reading raw data from registers...\n");
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
float x_accel, y_accel, z_accel, temp;
lis3dh_init();
while (1) {
lis3dh_read_data(0x28, &x_accel, true);
lis3dh_read_data(0x2A, &y_accel, true);
lis3dh_read_data(0x2C, &z_accel, true);
lis3dh_read_data(0x0C, &temp, false);
// Display data
printf("TEMPERATURE: %.3f%cC\n", temp, 176);
// Acceleration is read as a multiple of g (gravitational acceleration on the Earth's surface)
printf("ACCELERATION VALUES: \n");
printf("X acceleration: %.3fg\n", x_accel);
printf("Y acceleration: %.3fg\n", y_accel);
printf("Z acceleration: %.3fg\n", z_accel);
sleep_ms(500);
// Clear terminal
printf("\e[1;1H\e[2J");
}
#endif
return 0;
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

View File

@ -1,12 +0,0 @@
add_executable(mcp9808_i2c
mcp9808_i2c.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(mcp9808_i2c pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(mcp9808_i2c)
# add url via pico_set_program_url
example_auto_set_url(mcp9808_i2c)

View File

@ -1,34 +0,0 @@
= Attaching a MCP9808 digital temperature sensor via I2C
This example code shows how to interface the Raspberry Pi Pico to the MCP9808 digital temperature sensor board.
This example reads the ambient temperature value each second from the sensor and sets upper, lower and critical limits for the temperature and checks if alerts need to be raised. The CONFIG register can also be used to check for an alert if the critical temperature is surpassed.
== Wiring information
Wiring up the device requires 4 jumpers, to connect VDD, GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the VSYS pin.
[[mcp9808_i2c_wiring]]
[pdfwidth=75%]
.Wiring Diagram for MCP9808.
image::mcp9808_i2c.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
mcp9808_i2c.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[mcp9808-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| MCP9808 board| 1 | https://www.adafruit.com/product/1782
| M/M Jumper wires | 4 | generic part
|===

View File

@ -1,147 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
/* Example code to talk to a MCP9808 ±0.5°C Digital temperature Sensor
This reads and writes to registers on the board.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is GP4 (physical pin 6)) -> SDA on MCP9808 board
GPIO PICO_DEFAULT_I2C_SCK_PIN (On Pico this is GP5 (physcial pin 7)) -> SCL on MCP9808 board
Vsys (physical pin 39) -> VDD on MCP9808 board
GND (physical pin 38) -> GND on MCP9808 board
*/
//The bus address is determined by the state of pins A0, A1 and A2 on the MCP9808 board
static uint8_t ADDRESS = 0x18;
//hardware registers
const uint8_t REG_POINTER = 0x00;
const uint8_t REG_CONFIG = 0x01;
const uint8_t REG_TEMP_UPPER = 0x02;
const uint8_t REG_TEMP_LOWER = 0x03;
const uint8_t REG_TEMP_CRIT = 0x04;
const uint8_t REG_TEMP_AMB = 0x05;
const uint8_t REG_RESOLUTION = 0x08;
void mcp9808_check_limits(uint8_t upper_byte) {
// Check flags and raise alerts accordingly
if ((upper_byte & 0x40) == 0x40) { //TA > TUPPER
printf("Temperature is above the upper temperature limit.\n");
}
if ((upper_byte & 0x20) == 0x20) { //TA < TLOWER
printf("Temperature is below the lower temperature limit.\n");
}
if ((upper_byte & 0x80) == 0x80) { //TA > TCRIT
printf("Temperature is above the critical temperature limit.\n");
}
}
float mcp9808_convert_temp(uint8_t upper_byte, uint8_t lower_byte) {
float temperature;
//Check if TA <= 0°C and convert to denary accordingly
if ((upper_byte & 0x10) == 0x10) {
upper_byte = upper_byte & 0x0F;
temperature = 256 - (((float) upper_byte * 16) + ((float) lower_byte / 16));
} else {
temperature = (((float) upper_byte * 16) + ((float) lower_byte / 16));
}
return temperature;
}
#ifdef i2c_default
void mcp9808_set_limits() {
//Set an upper limit of 30°C for the temperature
uint8_t upper_temp_msb = 0x01;
uint8_t upper_temp_lsb = 0xE0;
//Set a lower limit of 20°C for the temperature
uint8_t lower_temp_msb = 0x01;
uint8_t lower_temp_lsb = 0x40;
//Set a critical limit of 40°C for the temperature
uint8_t crit_temp_msb = 0x02;
uint8_t crit_temp_lsb = 0x80;
uint8_t buf[3];
buf[0] = REG_TEMP_UPPER;
buf[1] = upper_temp_msb;
buf[2] = upper_temp_lsb;
i2c_write_blocking(i2c_default, ADDRESS, buf, 3, false);
buf[0] = REG_TEMP_LOWER;
buf[1] = lower_temp_msb;
buf[2] = lower_temp_lsb;
i2c_write_blocking(i2c_default, ADDRESS, buf, 3, false);
buf[0] = REG_TEMP_CRIT;
buf[1] = crit_temp_msb;
buf[2] = crit_temp_lsb;;
i2c_write_blocking(i2c_default, ADDRESS, buf, 3, false);
}
#endif
int main() {
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/mcp9808_i2c example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
printf("Hello, MCP9808! Reading raw data from registers...\n");
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
mcp9808_set_limits();
uint8_t buf[2];
uint16_t upper_byte;
uint16_t lower_byte;
float temperature;
while (1) {
// Start reading ambient temperature register for 2 bytes
i2c_write_blocking(i2c_default, ADDRESS, &REG_TEMP_AMB, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, buf, 2, false);
upper_byte = buf[0];
lower_byte = buf[1];
//isolates limit flags in upper byte
mcp9808_check_limits(upper_byte & 0xE0);
//clears flag bits in upper byte
temperature = mcp9808_convert_temp(upper_byte & 0x1F, lower_byte);
printf("Ambient temperature: %.4f°C\n", temperature);
sleep_ms(1000);
}
#endif
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View File

@ -1,11 +0,0 @@
add_executable(mma8451_i2c
mma8451_i2c.c
)
# pull in common dependencies and additional i2c hardware support
target_link_libraries(mma8451_i2c pico_stdlib hardware_i2c)
# create map/bin/hex file etc.
pico_add_extra_outputs(mma8451_i2c)
# add url via pico_set_program_url
example_auto_set_url(mma8451_i2c)

View File

@ -1,36 +0,0 @@
= Attaching a MMA8451 3-axis digital accelerometer via I2C
This example code shows how to interface the Raspberry Pi Pico to the MMA8451 digital accelerometer sensor board.
This example reads and displays the acceleration values of the board in the 3 axis. It also allows the user to set the trade-off between the range and precision based on the values they require. Values often have an offset which can be accounted for by writing to the offset correction registers. The datasheet for the sensor can be found at https://cdn-shop.adafruit.com/datasheets/MMA8451Q-1.pdf for additional information.
== Wiring information
Wiring up the device requires 4 jumpers, to connect VIN, GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the VSYS pin.
[[mma8451_i2c_wiring]]
[pdfwidth=75%]
.Wiring Diagram for MMA8451.
image::mma8451_i2c.png[]
== List of Files
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
mma8451_i2c.c:: The example code.
== Bill of Materials
.A list of materials required for the example
[[mma8451-bom-table]]
[cols=3]
|===
| *Item* | *Quantity* | Details
| Breadboard | 1 | generic part
| Raspberry Pi Pico | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
| MMA8451 board| 1 | https://www.adafruit.com/product/2019
| M/M Jumper wires | 4 | generic part
|===

View File

@ -1,128 +0,0 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
/* Example code to talk to a MMA8451 triple-axis accelerometer.
This reads and writes to registers on the board.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is GP4 (physical pin 6)) -> SDA on MMA8451 board
GPIO PICO_DEFAULT_I2C_SCK_PIN (On Pico this is GP5 (physcial pin 7)) -> SCL on MMA8451 board
VSYS (physical pin 39) -> VDD on MMA8451 board
GND (physical pin 38) -> GND on MMA8451 board
*/
const uint8_t ADDRESS = 0x1D;
//hardware registers
const uint8_t REG_X_MSB = 0x01;
const uint8_t REG_X_LSB = 0x02;
const uint8_t REG_Y_MSB = 0x03;
const uint8_t REG_Y_LSB = 0x04;
const uint8_t REG_Z_MSB = 0x05;
const uint8_t REG_Z_LSB = 0x06;
const uint8_t REG_DATA_CFG = 0x0E;
const uint8_t REG_CTRL_REG1 = 0x2A;
// Set the range and precision for the data
const uint8_t range_config = 0x01; // 0x00 for ±2g, 0x01 for ±4g, 0x02 for ±8g
const float count = 2048; // 4096 for ±2g, 2048 for ±4g, 1024 for ±8g
uint8_t buf[2];
float mma8451_convert_accel(uint16_t raw_accel) {
float acceleration;
// Acceleration is read as a multiple of g (gravitational acceleration on the Earth's surface)
// Check if acceleration < 0 and convert to decimal accordingly
if ((raw_accel & 0x2000) == 0x2000) {
raw_accel &= 0x1FFF;
acceleration = (-8192 + (float) raw_accel) / count;
} else {
acceleration = (float) raw_accel / count;
}
acceleration *= 9.81f;
return acceleration;
}
#ifdef i2c_default
void mma8451_set_state(uint8_t state) {
buf[0] = REG_CTRL_REG1;
buf[1] = state; // Set RST bit to 1
i2c_write_blocking(i2c_default, ADDRESS, buf, 2, false);
}
#endif
int main() {
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/mma8451_i2c example requires a board with I2C pins
puts("Default I2C pins were not defined");
#else
printf("Hello, MMA8451! Reading raw data from registers...\n");
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
float x_acceleration;
float y_acceleration;
float z_acceleration;
// Enable standby mode
mma8451_set_state(0x00);
// Edit configuration while in standby mode
buf[0] = REG_DATA_CFG;
buf[1] = range_config;
i2c_write_blocking(i2c_default, ADDRESS, buf, 2, false);
// Enable active mode
mma8451_set_state(0x01);
while (1) {
// Start reading acceleration registers for 2 bytes
i2c_write_blocking(i2c_default, ADDRESS, &REG_X_MSB, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, buf, 2, false);
x_acceleration = mma8451_convert_accel(buf[0] << 6 | buf[1] >> 2);
i2c_write_blocking(i2c_default, ADDRESS, &REG_Y_MSB, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, buf, 2, false);
y_acceleration = mma8451_convert_accel(buf[0] << 6 | buf[1] >> 2);
i2c_write_blocking(i2c_default, ADDRESS, &REG_Z_MSB, 1, true);
i2c_read_blocking(i2c_default, ADDRESS, buf, 2, false);
z_acceleration = mma8451_convert_accel(buf[0] << 6 | buf[1] >> 2);
// Display acceleration values
printf("ACCELERATION VALUES: \n");
printf("X acceleration: %.6fms^-2\n", x_acceleration);
printf("Y acceleration: %.6fms^-2\n", y_acceleration);
printf("Z acceleration: %.6fms^-2\n", z_acceleration);
sleep_ms(500);
// Clear terminal
printf("\e[1;1H\e[2J");
}
#endif
}

Some files were not shown because too many files have changed in this diff Show More