Initial commit: most infrastructure already done
- 7-segment display controlled via PIO and DMA - buzzer works with PWM - millisecond trigger interrupt works
This commit is contained in:
commit
a4e935692a
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
.cache/
|
33
CMakeLists.txt
Normal file
33
CMakeLists.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
cmake_minimum_required (VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project (zam_power_timer VERSION 0.1 LANGUAGES C CXX ASM)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME}
|
||||
src/main.c
|
||||
src/sseg.c
|
||||
src/sseg.h
|
||||
src/pinout.h
|
||||
src/sseg.pio
|
||||
)
|
||||
|
||||
pico_generate_pio_header(zam_power_timer ${CMAKE_CURRENT_LIST_DIR}/src/sseg.pio)
|
||||
|
||||
|
||||
pico_enable_stdio_usb(${CMAKE_PROJECT_NAME} 1)
|
||||
pico_enable_stdio_uart(${CMAKE_PROJECT_NAME} 0)
|
||||
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
pico_stdlib
|
||||
hardware_pwm
|
||||
hardware_timer
|
||||
hardware_irq
|
||||
hardware_pio
|
||||
hardware_dma)
|
1
compile_commands.json
Symbolic link
1
compile_commands.json
Symbolic link
|
@ -0,0 +1 @@
|
|||
build/compile_commands.json
|
16
doc/sseg_codes.txt
Normal file
16
doc/sseg_codes.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
7654 3210 Hex
|
||||
ABCDEFGP PCBA DEFG
|
||||
Z: 11011010 0011 1101 0x3C
|
||||
A: 11101110 0111 0111 0x77
|
||||
M: 11101100 0111 0110 0x76
|
||||
|
||||
0: 11111100 0111 1110 0x7E
|
||||
1: 01100000 0110 0000 0x60
|
||||
2: 11011010 0011 1101 0x3D
|
||||
3: 11110010 0111 1001 0x79
|
||||
4: 01100110 0110 0011 0x63
|
||||
5: 10110110 0101 1011 0x5B
|
||||
6: 10111110 0101 1111 0x5F
|
||||
7: 11100000 0111 0000 0x70
|
||||
8: 11111110 0111 1111 0x7F
|
||||
9: 11110110 0111 1011 0x7B
|
8
make.sh
Executable file
8
make.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
export PICO_SDK_PATH=/home/thomas/Software/rpi-pico/pico-sdk
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
|
||||
make $@
|
73
pico_sdk_import.cmake
Normal file
73
pico_sdk_import.cmake
Normal file
|
@ -0,0 +1,73 @@
|
|||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
118
src/main.c
Normal file
118
src/main.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/pwm.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#include "sseg.h"
|
||||
#include "pinout.h"
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
const uint8_t all_gpios[] = {
|
||||
OUTPUT_ENABLE_PIN,
|
||||
};
|
||||
|
||||
static volatile bool m_ms_triggered;
|
||||
static uint32_t m_next_ms_trigger;
|
||||
|
||||
#define MS_TRIG_ALARM_NUM 0
|
||||
#define MS_TRIG_ALARM_IRQ TIMER_IRQ_0
|
||||
|
||||
static void arm_ms_trig_alarm(void)
|
||||
{
|
||||
m_next_ms_trigger += 1000; // microseconds
|
||||
timer_hw->alarm[MS_TRIG_ALARM_NUM] = m_next_ms_trigger;
|
||||
}
|
||||
|
||||
static void alarm_irq(void)
|
||||
{
|
||||
// Clear the alarm irq
|
||||
hw_clear_bits(&timer_hw->intr, 1u << MS_TRIG_ALARM_NUM);
|
||||
|
||||
// set the next alarm
|
||||
arm_ms_trig_alarm();
|
||||
|
||||
// Assume alarm 0 has fired
|
||||
m_ms_triggered = true;
|
||||
}
|
||||
|
||||
static void configure_ms_trig_alarm(void)
|
||||
{
|
||||
m_ms_triggered = false;
|
||||
hw_set_bits(&timer_hw->inte, 1u << MS_TRIG_ALARM_NUM);
|
||||
irq_set_exclusive_handler(MS_TRIG_ALARM_IRQ, alarm_irq);
|
||||
irq_set_enabled(MS_TRIG_ALARM_IRQ, true);
|
||||
m_next_ms_trigger = timer_hw->timelr + 10000;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
//stdio_init_all();
|
||||
//printf("Hello, world!\n");
|
||||
|
||||
bool power_switch_state = false;
|
||||
|
||||
for(size_t i = 0; i < sizeof(all_gpios); i++) {
|
||||
gpio_init(all_gpios[i]);
|
||||
gpio_put(all_gpios[i], false);
|
||||
gpio_set_dir(all_gpios[i], true);
|
||||
}
|
||||
|
||||
gpio_put(OUTPUT_ENABLE_PIN, true);
|
||||
|
||||
// set up PWM for 50 kHz @ 512 steps resolution
|
||||
uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN);
|
||||
|
||||
pwm_set_clkdiv_int_frac(slice_num, 244, (14 << 4) / 100); // 125 MHz / 244.14 / 512 = 1 kHz
|
||||
gpio_set_function(BUZZER_PIN, GPIO_FUNC_PWM);
|
||||
pwm_set_wrap(slice_num, 512);
|
||||
pwm_set_chan_level(slice_num, PWM_CHAN_B, 1 * 512 / 100);
|
||||
pwm_set_enabled(slice_num, true);
|
||||
|
||||
sleep_ms(200);
|
||||
|
||||
pwm_set_enabled(slice_num, false);
|
||||
pwm_set_clkdiv_int_frac(slice_num, 122, (7 << 4) / 100); // 125 MHz / 122.07 / 512 = 2 kHz
|
||||
pwm_set_enabled(slice_num, true);
|
||||
|
||||
|
||||
sleep_ms(200);
|
||||
|
||||
pwm_set_enabled(slice_num, false);
|
||||
pwm_set_clkdiv_int_frac(slice_num, 61, (3 << 4) / 100); // 125 MHz / 61.03 / 512 = 4 kHz
|
||||
pwm_set_enabled(slice_num, true);
|
||||
|
||||
sleep_ms(200);
|
||||
|
||||
pwm_set_enabled(slice_num, false);
|
||||
gpio_init(BUZZER_PIN);
|
||||
gpio_put(BUZZER_PIN, false);
|
||||
gpio_set_dir(BUZZER_PIN, true);
|
||||
|
||||
sleep_ms(2400);
|
||||
|
||||
pwm_set_enabled(slice_num, false);
|
||||
gpio_init(BUZZER_PIN);
|
||||
|
||||
gpio_put(OUTPUT_ENABLE_PIN, false);
|
||||
|
||||
sseg_init();
|
||||
|
||||
configure_ms_trig_alarm();
|
||||
arm_ms_trig_alarm();
|
||||
|
||||
uint32_t ms_counter = 0;
|
||||
while (true) {
|
||||
sseg_loop();
|
||||
|
||||
if(m_ms_triggered) {
|
||||
m_ms_triggered = false;
|
||||
|
||||
ms_counter++;
|
||||
sseg_set_char(2, '0' + (ms_counter / 100) % 10, false);
|
||||
sseg_set_char(1, '0' + (ms_counter / 1000) % 10, true);
|
||||
sseg_set_char(0, '0' + (ms_counter / 10000) % 10, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
22
src/pinout.h
Normal file
22
src/pinout.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef PINOUT_H
|
||||
#define PINOUT_H
|
||||
|
||||
#define OUTPUT_ENABLE_PIN 22
|
||||
|
||||
#define SSEG_MUX_1_PIN 8
|
||||
#define SSEG_MUX_2_PIN 9
|
||||
#define SSEG_MUX_3_PIN 10
|
||||
|
||||
#define SSEG_A_PIN 4
|
||||
#define SSEG_B_PIN 5
|
||||
#define SSEG_C_PIN 6
|
||||
#define SSEG_D_PIN 3
|
||||
#define SSEG_E_PIN 2
|
||||
#define SSEG_F_PIN 1
|
||||
#define SSEG_G_PIN 0
|
||||
#define SSEG_DP_PIN 7
|
||||
|
||||
#define BUZZER_PIN 11
|
||||
|
||||
|
||||
#endif // PINOUT_H
|
145
src/sseg.c
Normal file
145
src/sseg.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include "hardware/gpio.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/dma.h"
|
||||
|
||||
#include "sseg.pio.h"
|
||||
|
||||
#include "sseg.h"
|
||||
#include "pinout.h"
|
||||
|
||||
// Segment Layout:
|
||||
//
|
||||
// .--A--.
|
||||
// | |
|
||||
// F B
|
||||
// | |
|
||||
// +--G--+
|
||||
// | |
|
||||
// E C
|
||||
// | |
|
||||
// .--D--. .DP.
|
||||
|
||||
|
||||
#define SSEG_START_PIN 0
|
||||
|
||||
static volatile uint32_t m_dma_buffer[4] __attribute__((aligned(4*sizeof(uint32_t *)))) = {
|
||||
0x0000013D, // segment 0 = 'Z' = '2'
|
||||
0x00000277, // segment 1 = A
|
||||
0x00000476, // segment 2 = M
|
||||
0x00000000, // dummy entry
|
||||
};
|
||||
|
||||
static PIO m_pio;
|
||||
static uint m_sm;
|
||||
|
||||
static int m_dma_chan;
|
||||
|
||||
static uint8_t ascii_to_sseg(char c)
|
||||
{
|
||||
switch(c) {
|
||||
case '0':
|
||||
return 0x7E;
|
||||
|
||||
case '1':
|
||||
return 0x60;
|
||||
|
||||
case 'Z':
|
||||
case '2':
|
||||
return 0x3D;
|
||||
|
||||
case '3':
|
||||
return 0x79;
|
||||
|
||||
case '4':
|
||||
return 0x63;
|
||||
|
||||
case '5':
|
||||
return 0x5B;
|
||||
|
||||
case '6':
|
||||
return 0x5F;
|
||||
|
||||
case '7':
|
||||
return 0x70;
|
||||
|
||||
case '8':
|
||||
return 0x7F;
|
||||
|
||||
case '9':
|
||||
return 0x7B;
|
||||
|
||||
case 'M':
|
||||
return 0x76;
|
||||
|
||||
case 'A':
|
||||
return 0x77;
|
||||
|
||||
default: // '-'
|
||||
return 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
void sseg_init(void)
|
||||
{
|
||||
// set up PIO for 7-segment display
|
||||
m_pio = pio0;
|
||||
uint offset = pio_add_program(m_pio, &sseg_program);
|
||||
m_sm = pio_claim_unused_sm(m_pio, true);
|
||||
pio_sm_config c = sseg_program_get_default_config(offset);
|
||||
|
||||
sm_config_set_clkdiv_int_frac(&c, 2000, 0);
|
||||
|
||||
sm_config_set_out_pins(&c, SSEG_START_PIN, 11);
|
||||
sm_config_set_set_pins(&c, SSEG_START_PIN+8, 3);
|
||||
|
||||
pio_gpio_init(m_pio, SSEG_A_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_B_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_C_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_D_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_E_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_F_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_G_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_DP_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_MUX_1_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_MUX_2_PIN);
|
||||
pio_gpio_init(m_pio, SSEG_MUX_3_PIN);
|
||||
|
||||
pio_sm_set_consecutive_pindirs(m_pio, m_sm, SSEG_START_PIN, 11, true);
|
||||
|
||||
pio_sm_init(m_pio, m_sm, offset, &c);
|
||||
|
||||
m_dma_chan = dma_claim_unused_channel(true);
|
||||
dma_channel_config dma_config = dma_channel_get_default_config(m_dma_chan);
|
||||
|
||||
channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32);
|
||||
channel_config_set_read_increment(&dma_config, true);
|
||||
channel_config_set_write_increment(&dma_config, false);
|
||||
channel_config_set_ring(&dma_config, false, 4); // read ringbuffer with 2^4 = 16 bytes = 4 entries
|
||||
channel_config_set_dreq(&dma_config, DREQ_PIO0_TX0);
|
||||
|
||||
dma_channel_configure(
|
||||
m_dma_chan,
|
||||
&dma_config,
|
||||
&pio0_hw->txf[0], // Write address (only need to set this once)
|
||||
m_dma_buffer, // Read address
|
||||
1<<14, // Write the buffer many times, then halt and interrupt
|
||||
true // Start right now
|
||||
);
|
||||
|
||||
pio_sm_set_enabled(m_pio, m_sm, true);
|
||||
}
|
||||
|
||||
void sseg_loop(void)
|
||||
{
|
||||
// restart the DMA channel if it has completed the transfer
|
||||
if((dma_hw->intr & (1u << m_dma_chan)) != 0) {
|
||||
dma_hw->ints0 = 1u << m_dma_chan;
|
||||
dma_channel_start(m_dma_chan);
|
||||
}
|
||||
}
|
||||
|
||||
void sseg_set_char(uint8_t seg, char c, bool with_dot)
|
||||
{
|
||||
uint dot_bit = with_dot ? 0x80 : 0x00;
|
||||
m_dma_buffer[seg] = (m_dma_buffer[seg] & 0xFFFFFF00) | dot_bit | ascii_to_sseg(c);
|
||||
}
|
12
src/sseg.h
Normal file
12
src/sseg.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef SSEG_H
|
||||
#define SSEG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void sseg_init(void);
|
||||
void sseg_loop(void);
|
||||
|
||||
void sseg_set_char(uint8_t seg, char c, bool with_dot);
|
||||
|
||||
#endif // SSEG_H
|
10
src/sseg.pio
Normal file
10
src/sseg.pio
Normal file
|
@ -0,0 +1,10 @@
|
|||
.program sseg
|
||||
|
||||
; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is
|
||||
; empty. Write the least significant bit to the OUT pin group.
|
||||
|
||||
loop:
|
||||
set pins, 0x00 ; set MUX pins to 0
|
||||
pull
|
||||
out pins, 11 [31] ; write the data from the FIFO to the outputs and wait some time
|
||||
jmp loop [31] ; repeat and wait some extra time
|
Loading…
Reference in a new issue