kopia lustrzana https://github.com/oddwires/RP2040-code
Various updates
rodzic
0226b83b60
commit
9ee02ab3c9
|
@ -1,24 +1,81 @@
|
|||
add_executable(FunctionGenerator)
|
||||
pico_generate_pio_header(FunctionGenerator ${CMAKE_CURRENT_LIST_DIR}/blink.pio)
|
||||
pico_generate_pio_header(FunctionGenerator ${CMAKE_CURRENT_LIST_DIR}/DAC.pio)
|
||||
# Generated Cmake Pico project file
|
||||
|
||||
# pull in common dependencies
|
||||
target_sources(FunctionGenerator PRIVATE FunctionGenerator.cpp)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# pull in common dependencies and additional spi hardware support
|
||||
target_link_libraries(FunctionGenerator PRIVATE
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Initialise pico_sdk from installed location
|
||||
# (note this can come from environment, CMake cache etc)
|
||||
|
||||
# == DO NEVER EDIT THE NEXT LINES for Raspberry Pi Pico VS Code Extension to work ==
|
||||
if(WIN32)
|
||||
set(USERHOME $ENV{USERPROFILE})
|
||||
else()
|
||||
set(USERHOME $ENV{HOME})
|
||||
endif()
|
||||
set(sdkVersion 2.0.0)
|
||||
set(toolchainVersion 13_2_Rel1)
|
||||
set(picotoolVersion 2.0.0)
|
||||
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
|
||||
if (EXISTS ${picoVscode})
|
||||
include(${picoVscode})
|
||||
endif()
|
||||
# ====================================================================================
|
||||
set(PICO_BOARD pico CACHE STRING "Board type")
|
||||
|
||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(Function_Generator C CXX ASM)
|
||||
|
||||
# Initialise the Raspberry Pi Pico SDK
|
||||
pico_sdk_init()
|
||||
|
||||
# Add executable. Default name is the project name, version 0.1
|
||||
|
||||
add_executable(Function_Generator FunctionGenerator.cpp )
|
||||
|
||||
pico_set_program_name(Function_Generator "Function_Generator")
|
||||
pico_set_program_version(Function_Generator "0.1")
|
||||
|
||||
# Generate PIO header
|
||||
# NOTE: Ninja doesn't always work with relative paths, so best to replace with an absolute...
|
||||
# pico_generate_pio_header(Function_Generator ${CMAKE_CURRENT_LIST_DIR}/DAC.pio)
|
||||
pico_generate_pio_header(Function_Generator "C:/Github/Sandpit/RP2040-code/Function Generator/DAC.pio")
|
||||
|
||||
# pull in common dependencies...
|
||||
target_sources(Function_Generator PRIVATE
|
||||
DAC_Class.cpp
|
||||
FunctionGenerator.cpp
|
||||
ClockModule.cpp
|
||||
Demo.cpp
|
||||
SPI_Utils.cpp
|
||||
)
|
||||
|
||||
# Modify the below lines to enable/disable output over UART/USB
|
||||
pico_enable_stdio_uart(Function_Generator 0)
|
||||
pico_enable_stdio_usb(Function_Generator 1)
|
||||
|
||||
# Add the standard library to the build
|
||||
target_link_libraries(Function_Generator
|
||||
pico_stdlib
|
||||
hardware_pio
|
||||
hardware_dma
|
||||
hardware_spi)
|
||||
|
||||
# Add the standard include files to the build
|
||||
target_include_directories(Function_Generator PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
|
||||
)
|
||||
|
||||
# Add any user requested libraries
|
||||
target_link_libraries(Function_Generator
|
||||
hardware_spi
|
||||
hardware_dma
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
# enable usb output, disable uart output
|
||||
pico_enable_stdio_usb(FunctionGenerator 1)
|
||||
pico_enable_stdio_uart(FunctionGenerator 0)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(FunctionGenerator)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(FunctionGenerator)
|
||||
pico_add_extra_outputs(Function_Generator)
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
#include "ClockModule.h"
|
||||
|
||||
// Data for the clock face has been generated externally using an Excel spreadsheet...
|
||||
uint8_t FaceX[] = {
|
||||
0xfa,0xfb,0xfc,0xfd,0xfe,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfc,0xfc,0xfb,0xfb,0xfa,0xfa,0xf9,0xf8,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf3,0xf2,0xf1,0xf0,0xef,0xe9,0xea,0xeb,0xec,0xed,0xed,0xec,0xeb,0xea,0xe9,0xe7,0xe6,0xe5,0xe3,0xe2,0xe1,0xdf,0xde,0xdc,0xdb,0xd9,0xd8,0xd6,0xd4,0xd3,0xd1,0xcf,0xcd,0xcc,0xca,0xc8,0xc6,0xc4,0xc3,0xc1,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xad,0xab,0xa9,0xa6,0xa4,0xa2,0xa0,0x9e,0x9c,0x9a,0x97,0x95,0x93,0x91,0x8f,0x8c,0x8a,0x88,0x86,0x83,0x81,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7d,0x7b,0x78,0x76,0x74,0x72,0x6f,0x6d,0x6b,0x69,0x67,0x64,0x62,0x60,0x5e,0x5c,0x5a,0x58,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47,0x45,0x43,0x41,0x42,0x41,0x41,0x40,0x40,0x3f,0x3d,0x3b,0x3a,0x38,0x36,0x34,0x32,0x31,0x2f,0x2d,0x2b,0x2a,0x28,0x26,0x25,0x23,0x22,0x20,0x1f,0x1d,0x1c,0x1b,0x19,0x18,0x17,0x15,0x14,0x13,0x12,0x15,0x14,0x13,0x12,0x11,0x11,0x0f,0x0e,0x0d,0x0c,0x0b,0x0b,0x0a,0x09,0x08,0x07,0x06,0x06,0x05,0x04,0x04,0x03,0x03,0x02,
|
||||
0x02,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x04,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0b,0x0c,0x0d,0x0e,0x0f,0x15,0x14,0x13,0x12,0x11,0x11,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1b,0x1c,0x1d,0x1f,0x20,0x22,0x23,0x25,0x26,0x28,0x2a,0x2b,0x2d,0x2f,0x31,0x32,0x34,0x36,0x38,0x3a,0x3b,0x3d,0x42,0x41,0x41,0x40,0x40,0x3f,0x41,0x43,0x45,0x47,0x49,0x4b,0x4d,0x4f,0x51,0x53,0x55,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x67,0x69,0x6b,0x6d,0x6f,0x72,0x74,0x76,0x78,0x7b,0x7d,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x81,0x83,0x86,0x88,0x8a,0x8c,0x8f,0x91,0x93,0x95,0x97,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa9,0xab,0xad,0xaf,0xb1,0xb3,0xb5,0xb7,0xb9,0xbb,0xbd,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xc1,0xc3,0xc4,0xc6,0xc8,0xca,0xcc,0xcd,0xcf,0xd1,0xd3,0xd4,0xd6,0xd8,0xd9,0xdb,0xdc,0xde,0xdf,0xe1,0xe2,0xe3,0xe5,0xe6,0xe7,0xe9,0xea,0xeb,0xec,0xe9,0xea,0xeb,0xec,0xed,0xed,0xef,0xf0,0xf1,0xf2,0xf3,0xf3,0xf4,0xf5,
|
||||
0xf6,0xf7,0xf8,0xf8,0xf9,0xfa,0xfa,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0c,0x0c,0x0c,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x0e,0x0d,0x0c,0x0c,0x0c,0x0c,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x52,0x51,0x50,0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x46,0x46,0x46,0x46,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,
|
||||
0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x50,0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x82,0x81,0x80,0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x77,0x77,0x77,0x77,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xe0,0xe1,0xe2,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe2,0xe1,0xe0,0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,0xe1,0xe2,0xe3,0xe3,0xe3,0xe3,0xe2,0xe1,0xe0,0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd7,0xd7,0xd7,0xd8,0xd9,0xf0,0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe5,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
|
||||
0xeb,0xec,0xed,0xee,0xef,0xf0,0xf0,0xf0,0xf0,0xf0,0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe5,0xe4,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd0,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x81,0x80,0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x75,0x75,0x75,0x75,0x75,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x80,0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x75,} ;
|
||||
uint8_t FaceY[] = {
|
||||
0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7d,0x7b,0x78,0x76,0x74,0x72,0x6f,0x6d,0x6b,0x69,0x67,0x64,0x62,0x60,0x5e,0x5c,0x5a,0x58,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47,0x45,0x43,0x41,0x42,0x41,0x41,0x40,0x40,0x3f,0x3d,0x3b,0x3a,0x38,0x36,0x34,0x32,0x31,0x2f,0x2d,0x2b,0x2a,0x28,0x26,0x25,0x23,0x22,0x20,0x1f,0x1d,0x1c,0x1b,0x19,0x18,0x17,0x15,0x14,0x13,0x12,0x15,0x14,0x13,0x12,0x11,0x11,0x0f,0x0e,0x0d,0x0c,0x0b,0x0b,0x0a,0x09,0x08,0x07,0x06,0x06,0x05,0x04,0x04,0x03,0x03,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x04,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0b,0x0c,0x0d,0x0e,0x0f,0x15,0x14,0x13,0x12,0x11,0x11,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1b,0x1c,0x1d,0x1f,0x20,0x22,0x23,0x25,0x26,0x28,0x2a,0x2b,0x2d,0x2f,0x31,0x32,0x34,0x36,0x38,0x3a,0x3b,0x3d,0x42,0x41,0x41,0x40,0x40,0x3f,0x41,0x43,0x45,0x47,0x49,0x4b,0x4d,0x4f,0x51,0x53,0x55,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,
|
||||
0x67,0x69,0x6b,0x6d,0x6f,0x72,0x74,0x76,0x78,0x7b,0x7d,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x81,0x83,0x86,0x88,0x8a,0x8c,0x8f,0x91,0x93,0x95,0x97,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa9,0xab,0xad,0xaf,0xb1,0xb3,0xb5,0xb7,0xb9,0xbb,0xbd,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xc1,0xc3,0xc4,0xc6,0xc8,0xca,0xcc,0xcd,0xcf,0xd1,0xd3,0xd4,0xd6,0xd8,0xd9,0xdb,0xdc,0xde,0xdf,0xe1,0xe2,0xe3,0xe5,0xe6,0xe7,0xe9,0xea,0xeb,0xec,0xe9,0xea,0xeb,0xec,0xed,0xed,0xef,0xf0,0xf1,0xf2,0xf3,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf8,0xf9,0xfa,0xfa,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfc,0xfc,0xfb,0xfb,0xfa,0xfa,0xf9,0xf8,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf3,0xf2,0xf1,0xf0,0xef,0xe9,0xea,0xeb,0xec,0xed,0xed,0xec,0xeb,0xea,0xe9,0xe7,0xe6,0xe5,0xe3,0xe2,0xe1,0xdf,0xde,0xdc,0xdb,0xd9,0xd8,0xd6,0xd4,0xd3,0xd1,0xcf,0xcd,0xcc,0xca,0xc8,0xc6,0xc4,0xc3,0xc1,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,
|
||||
0xad,0xab,0xa9,0xa6,0xa4,0xa2,0xa0,0x9e,0x9c,0x9a,0x97,0x95,0x93,0x91,0x8f,0x8c,0x8a,0x88,0x86,0x83,0x81,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x3e,0x3d,0x3c,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x78,0x77,0x76,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x88,0x87,0x86,0xb3,0xb2,0xb1,0xb0,0xaf,0xae,0xad,0xac,0xab,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xe2,0xe3,0xe4,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0,0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,
|
||||
0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xe0,0xdf,0xde,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xde,0xdf,0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf0,0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe7,0xe8,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0,0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb2,0xb1,0xb0,0xaf,0xae,0xad,0xac,0xab,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0x87,0x88,0x89,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83,0x82,0x81,0x80,0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x76,0x76,0x76,
|
||||
0x76,0x76,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7f,0x7e,0x7d,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x4d,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40,0x3f,0x3e,0x3d,0x3c,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x0e,0x0d,0x0c,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,} ;
|
||||
// (Number of pixels: 1000)
|
||||
|
||||
// Storage for clock hands co-ordinates...
|
||||
uint8_t HandsX[192] = {} ; // Each hand requires 64 bytes - 3x64=192
|
||||
uint8_t HandsY[192] = {} ;
|
||||
|
||||
void HlpTxt(char c); // Forward deffinition
|
||||
|
||||
void ClockModule ( DAC DACobj[] ) {
|
||||
char c;
|
||||
bool InvX=false, InvY=false ; // Clock display mode flags to allow inverted output
|
||||
uint32_t GPIO_mask_X=0x0ff<<DAC_A_Start ; // Mask defining which GPIO's connect to the R2R networks
|
||||
uint32_t GPIO_mask_Y=0x0ff<<DAC_B_Start ;
|
||||
|
||||
printf("\nClock>") ; // Clock module cursor
|
||||
|
||||
// Disable the Ctrl channels...
|
||||
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_A].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_B].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
// wait for Busy flag to clear...
|
||||
|
||||
// Abort the data channels...
|
||||
dma_channel_abort(DACobj[_DAC_A].data_chan);
|
||||
dma_channel_abort(DACobj[_DAC_B].data_chan);
|
||||
|
||||
// Re-enable the Ctrl channels (doesn't restart data transfer)...
|
||||
hw_set_bits(&dma_hw->ch[DACobj[_DAC_A].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
hw_set_bits(&dma_hw->ch[DACobj[_DAC_B].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
|
||||
pio_sm_set_enabled(_PIOnum_,0,false) ;
|
||||
pio_sm_set_enabled(_PIOnum_,1,false) ;
|
||||
|
||||
// Grab the GPIO from the State machines...
|
||||
for (uint i=0; i<8; i++) {
|
||||
gpio_init(DAC_A_Start + i);
|
||||
gpio_init(DAC_B_Start + i);
|
||||
gpio_set_dir(DAC_A_Start + i, GPIO_OUT);
|
||||
gpio_set_dir(DAC_B_Start + i, GPIO_OUT);
|
||||
}
|
||||
|
||||
_Result.Txt[0] = '\0' ; // String also used as a flag, so needs to be cleared
|
||||
// while (_Result.Txt[0] == '\0') { // exit on keypress
|
||||
while (true) { // exit on keypress
|
||||
float Radians ;
|
||||
int outX, outY ;
|
||||
// Draw the clock face...
|
||||
for (int i=0; i<sizeof(FaceX); i++) {
|
||||
outX=FaceX[i]*DACobj[_DAC_A].Level/100 ; // Scale output to match state machine settings
|
||||
outY=FaceY[i]*DACobj[_DAC_B].Level/100 ;
|
||||
if (!InvX) outX=255-outX ; // Invert output if selected
|
||||
if (!InvY) outY=255-outY ;
|
||||
outX=outX<<DAC_A_Start ; // Shift data bits to match R2R GPIO connections
|
||||
outY=outY<<DAC_B_Start ;
|
||||
gpio_put_masked(GPIO_mask_X,outX) ;
|
||||
gpio_put_masked(GPIO_mask_Y,outY) ;
|
||||
sleep_us(2) ; // Pause for on-screen persistance
|
||||
}
|
||||
// Draw the clock hands...
|
||||
for (int i=0; i<192; i++) { // 3 hands @ 64 pixels each = 192
|
||||
outX=HandsX[i]*DACobj[_DAC_A].Level/100 ; // Scale output to match state machine settings
|
||||
outY=HandsY[i]*DACobj[_DAC_B].Level/100 ;
|
||||
if (!InvX) outX=255-outX ; // Invert output if selected
|
||||
if (!InvY) outY=255-outY ;
|
||||
outX=outX<<DAC_A_Start ; // Shift data bits to match R2R GPIO connections
|
||||
outY=outY<<DAC_B_Start ;
|
||||
gpio_put_masked(GPIO_mask_X,outX) ;
|
||||
gpio_put_masked(GPIO_mask_Y,outY) ;
|
||||
sleep_us(2) ; // Pause for on-screen persistance
|
||||
}
|
||||
c = getchar_timeout_us(0); // Non-blocking char input
|
||||
if (c!=EOF) { // c=EOF if no input
|
||||
if ((c=='x') or (c=='X')) {
|
||||
InvX = !InvX ;
|
||||
if (InvX) printf("%c%sX axis inverted.",c,MarginVW) ; // Print current status
|
||||
else printf("%c%sX axis NOT inverted.",c,MarginVW) ;
|
||||
printf("\nClock>") ; // Cursor
|
||||
}
|
||||
else if ((c=='y') or (c=='Y')) {
|
||||
InvY = !InvY ;
|
||||
if (InvY) printf("%c%sY axis inverted.",c,MarginVW) ; // Print current status
|
||||
else printf("%c%sY axis NOT inverted.",c,MarginVW) ;
|
||||
printf("\nClock>") ; // Cursor
|
||||
}
|
||||
else if ((c=='S') or (c=='s')) { // Time set
|
||||
printf("%c%sSet time (format HH:MM:SS)...",c,MarginVW) ;
|
||||
getLine() ; // Get the console input
|
||||
Parm[0]=0, Parm[1]=0, Parm[2]=0, Parm[3]=0 ; // Reset all command line parameters
|
||||
int i=0, ParmCnt=0 ; // Reset all command line counters
|
||||
while (i<strlen(inStr) ) {
|
||||
if ((inStr[i]==':')||(inStr[i]==',')) { // Next parameter
|
||||
ParmCnt++ ; }
|
||||
else if (isdigit(inStr[i])) {
|
||||
Parm[ParmCnt] *= 10; // Next digit. Bump the existing decimal digits
|
||||
Parm[ParmCnt] += inStr[i] - '0'; } // Convert character to integer and add
|
||||
i++ ; // Next character
|
||||
}
|
||||
inStr[0]='\0' ; // Reset input buffer
|
||||
Hours=Parm[0]%24 ; Mins=Parm[1]%60 ; Secs=Parm[2]%60 ; // Set the time from parameters
|
||||
LEDctr=0 ; // Force update and do it on next tick
|
||||
printf("\n%s Clock set to %02d:%02d:%02d\nClock>",MarginVW,Hours,Mins,Secs) ;
|
||||
}
|
||||
else if ((c=='h') or (c=='H') or (c=='?')) HlpTxt(c);
|
||||
else if ((c=='q') or (c=='Q')) {
|
||||
for (uint i=0; i<8; i++) { // Hand the GPIO's back to the State machines
|
||||
pio_gpio_init(_PIOnum_, DAC_A_Start + i);
|
||||
pio_gpio_init(_PIOnum_, DAC_B_Start + i);
|
||||
}
|
||||
// Reset the data transfer DMA's to the start of the data Bitmap...
|
||||
dma_channel_set_read_addr(DACobj[_DAC_A].data_chan, &DACobj[_DAC_A].DAC_data[0], false);
|
||||
dma_channel_set_read_addr(DACobj[_DAC_B].data_chan, &DACobj[_DAC_B].DAC_data[0], false);
|
||||
pio_sm_set_enabled(_PIOnum_,0,true) ; // Re-enable State machine 0
|
||||
pio_sm_set_enabled(_PIOnum_,1,true) ; // Re-enable State machine 1
|
||||
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
|
||||
|
||||
sprintf(_Result.Txt,"%c%sQuit clock mode\n",c,MarginVW);// Prevents error message on return
|
||||
return; // exit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HlpTxt(char c) {
|
||||
// Print Help text aligned to current margin settings...
|
||||
// Note: Following string requires '%%%%' to print '%'
|
||||
// HelpText string is copied to _Result.Txt using sprintf - this reduces '%%%%' to '%%'
|
||||
// _Result.Txt is sent to terminal using printf - this reduces '%%' to '%'
|
||||
strcpy(MarginVW,Margin); // Re-initialise Variable Width margin...
|
||||
tmp = strlen(inStr) ; // Get number of command line characters
|
||||
if (tmp != 0) tmp ++; // Bump to allow for cursor.
|
||||
// Note: If called at Start-up there will be no input characters
|
||||
MarginVW[MWidth - tmp] = '\0' ; // Calculate padding required for command characters and cursor
|
||||
sprintf(_Result.Txt, "%c%sHelp...\n"
|
||||
"%s%sh/H/? - Help\n"
|
||||
"%s%sX - Invert X-axis\n"
|
||||
"%s%sY - Invert Y-axis\n"
|
||||
"%s%sS - Set time (format HH:MM:SS)\n"
|
||||
"%s%sQ - Quit (Return to Function Generator)\n"
|
||||
"\nClock>", // Cursor
|
||||
c, MarginVW, Margin, MarginVW, Margin, MarginVW, Margin,
|
||||
MarginVW, Margin, MarginVW, Margin, MarginVW ) ;
|
||||
printf(_Result.Txt) ; // Update terminal
|
||||
inStr[0] = '\0' ; // Reset input string
|
||||
*_Result.Txt = '\0' ;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "DAC_Class.h"
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
extern uint8_t FaceX[], FaceY[];
|
||||
extern uint8_t HandsX[], HandsY[];
|
||||
extern int tmp, LEDctr, Parm[], Hours, Mins, Secs;
|
||||
extern char MarginVW[], Margin[], inStr[];
|
||||
extern void getLine();
|
||||
extern struct repeating_timer timer;
|
|
@ -25,7 +25,7 @@ loop01: ; Loop will run 2
|
|||
// Note: 1) No divider is specified for the SM, so it will default to the same speed as the CPU.
|
||||
// 2) Hard coded to use 8 bit DAC hardware
|
||||
|
||||
void pio_DAC_program_init(PIO pio, uint sm, uint offset, uint start_pin) {
|
||||
inline void pio_DAC_program_init(PIO pio, uint sm, uint offset, uint start_pin) {
|
||||
for (uint i=start_pin; i<(start_pin+8); i++) { pio_gpio_init(pio, i); } // Allow PIO to control GPIO pins as outputs
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, start_pin, 8, true); // Set the pin direction to output (in PIO)
|
||||
pio_sm_config c = pio_DAC_program_get_default_config(offset); // Define PIO Configuration structure
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
// Each DAC channel consists of...
|
||||
// BitMap data => DMA => FIFO => State Machine => GPIO pins => R-2-R module
|
||||
// Note: The PIO clock dividers are 16-bit integer, 8-bit fractional, with first-order delta-sigma for the fractional divider.
|
||||
// This means the clock divisor can vary between 1 and 65536, in increments of 1/256.
|
||||
// If DAC_div exceeds 2^16 (65,536), the registers will wrap around, and the State Machine clock will be incorrect.
|
||||
// For frequencies below 34Hz, an additional 63 op-code delay is inserted into the State Machine assembler code. This slows
|
||||
// down the State Machine operation by a factor of 64, keeping the value of DAC_div within range.
|
||||
|
||||
#include "DAC_Class.h"
|
||||
#include "ClockModule.h"
|
||||
|
||||
DAC::DAC(char _name, PIO _pio, uint8_t _GPIO) {
|
||||
// DAC Constructor
|
||||
// Parameters...
|
||||
// _name = Name of this DAC channel instance
|
||||
// _pio = Required PIO channel
|
||||
// _GPIO = Port connecting to the MSB of the R-2-R resistor network.
|
||||
pio = _pio;
|
||||
PIOnum = pio_get_index(pio) ; // Printer friendly value
|
||||
GPIO = _GPIO ; // Initialse class value
|
||||
Funct = _Sine_, Freq = 100, Level = 50 ; // Start-up default values...
|
||||
Range = 1, Harm = 0, DutyC = 50, RiseT = 50, name = _name ;
|
||||
name == 'A' ? Phase=0 : Phase=180 ; // Set Phase difference between channels
|
||||
int _offset;
|
||||
|
||||
StateMachine = pio_claim_unused_sm(_pio, true); // Find a free state machine on the specified PIO - error if there are none.
|
||||
ctrl_chan = dma_claim_unused_channel(true); // Find 2 x free DMA channels for the DAC (12 available)
|
||||
data_chan = dma_claim_unused_channel(true);
|
||||
|
||||
// Configure the state machine to run the DAC program...
|
||||
_offset = pio_add_program(_pio, &pio_DAC_program); // Use helper function included in the .pio file.
|
||||
SM_WrapBot = _offset;
|
||||
pio_DAC_program_init(_pio, StateMachine, _offset, _GPIO);
|
||||
// Setup the DAC control channel...
|
||||
// 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 fc = dma_channel_get_default_config(ctrl_chan); // default configs
|
||||
channel_config_set_transfer_data_size(&fc, DMA_SIZE_32); // 32-bit txfers
|
||||
channel_config_set_read_increment(&fc, false); // no read incrementing
|
||||
channel_config_set_write_increment(&fc, false); // no write incrementing
|
||||
|
||||
// !!! THIS RESTRICTS SPEED TO ~730KHz !!!
|
||||
// fc.ctrl |= DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS; // Set high priority
|
||||
|
||||
dma_channel_configure(
|
||||
ctrl_chan,
|
||||
&fc,
|
||||
&dma_hw->ch[data_chan].al1_transfer_count_trig, // txfer to transfer count trigger
|
||||
&transfer_count,
|
||||
1,
|
||||
false
|
||||
);
|
||||
// Setup the DAC data channel...
|
||||
// 32 bit transfers. Read address increments after each transfer.
|
||||
fc = dma_channel_get_default_config(data_chan);
|
||||
channel_config_set_transfer_data_size(&fc, DMA_SIZE_32); // 32-bit txfers
|
||||
channel_config_set_read_increment(&fc, true); // increment the read adddress
|
||||
channel_config_set_write_increment(&fc, false); // don't increment write address
|
||||
channel_config_set_dreq(&fc, pio_get_dreq(_pio, StateMachine, true)); // Transfer when PIO SM TX FIFO has space
|
||||
channel_config_set_chain_to(&fc, ctrl_chan); // chain to the controller DMA channel
|
||||
channel_config_set_ring(&fc, false, 9); // 8 bit DAC 1<<9 byte boundary on read ptr. This is why we needed alignment!
|
||||
|
||||
// !!! THIS RESTRICTS SPEED TO ~730KHz !!!
|
||||
// fc.ctrl |= DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS; // Set high priority
|
||||
|
||||
dma_channel_configure(
|
||||
data_chan, // Channel to be configured
|
||||
&fc, // The configuration we just created
|
||||
&_pio->txf[StateMachine], // Write to FIFO
|
||||
DAC_data, // The initial read address (AT NATURAL ALIGNMENT POINT)
|
||||
BitMapSize, // Number of transfers; in this case each is 2 byte.
|
||||
false // Don't start immediately. All 4 control channels need to start simultaneously
|
||||
// to ensure the correct phase shift is applied.
|
||||
);
|
||||
DAC_channel_mask += (1u << ctrl_chan) ; // Save details of DMA control channel to global variable. This facilitates
|
||||
// atomic restarts of both channels, and ensures phase lock between channels.
|
||||
DataCalc() ; // Populate bitmap data.
|
||||
DACspeed(Freq * Range) ; // Initialise State Machine clock speed.
|
||||
};
|
||||
|
||||
char* DAC::StatusString() {
|
||||
// Report the status line for the current DAC object.
|
||||
char TmpStr[4];
|
||||
|
||||
if (Range == 1) strcpy(TmpStr," Hz") ; // Assign multiplier suffix
|
||||
if (Range == 1000) strcpy(TmpStr,"KHz") ;
|
||||
if (Range == 1000000) strcpy(TmpStr,"MHz") ;
|
||||
|
||||
switch ( Funct ) { // Calculate status sting...
|
||||
case _Sine_:
|
||||
sprintf(RetStr,"Channel %c: Freq:%3d%s Phase:%03d Level:%03d Wave:Sine Harmonic:%d\n",name, Freq, TmpStr, Phase, Level, Harm) ;
|
||||
return RetStr;
|
||||
case _Triangle_:
|
||||
if ((RiseT == 0) || (RiseT == 100)) {
|
||||
sprintf(RetStr,"Channel %c: Freq:%3d%s Phase:%03d Level:%03d Wave:Sawtooth\n",name, Freq, TmpStr, Phase, Level) ;
|
||||
} else {
|
||||
sprintf(RetStr,"Channel %c: Freq:%3d%s Phase:%03d Level:%03d Wave:Triangle Rise time:%d%%\n",name, Freq, TmpStr, Phase, Level, RiseT) ;
|
||||
}
|
||||
return RetStr;
|
||||
case _Square_:
|
||||
sprintf(RetStr,"Channel %c: Freq:%3d%s Phase:%03d Level:%03d Wave:Square Duty cycle:%d%%\n",name, Freq, TmpStr, Phase, Level, DutyC) ;
|
||||
return RetStr;
|
||||
default:
|
||||
return 0; // Program execution should never get here
|
||||
}
|
||||
}
|
||||
|
||||
int DAC::Set(int _type, int _val) {
|
||||
// Multi-purpose routine to set various DAC operating values.
|
||||
// Parameters...
|
||||
// _type = operating value to be set (frequency, phase, level, sine, square, triangle, time)
|
||||
// _val = value for the designated parameter
|
||||
_Result.Val = _val; // Save for SPI display
|
||||
switch (_type) {
|
||||
case _Freq_:
|
||||
Freq = _val ; // Frequency (numeric)
|
||||
DACspeed(Freq * Range) ; // Update State machine run speed
|
||||
break ;
|
||||
case _Phase_:
|
||||
Phase = _val ; // Phase shift (0->355 degrees)
|
||||
DataCalc() ; // Recalc Bitmap and apply new phase value
|
||||
break ;
|
||||
case _Level_:
|
||||
if (_val > 100) _val = 100 ; // Limit max val to 100%
|
||||
Level = _val ;
|
||||
MCP41020_Write(SelectedChan, Level) ; // Control byte for the MCP42010 just happens to be the same value as the SelectedChan variable
|
||||
StatusString() ; // Update the terminal session
|
||||
break ;
|
||||
case _Sine_:
|
||||
Funct = _Sine_ ;
|
||||
Harm = _val ; // Optional command line parameter (default to zero if not provided)
|
||||
DataCalc() ;
|
||||
break ;
|
||||
case _Square_:
|
||||
Funct = _Square_ ;
|
||||
DutyC = _val ; // Optional command line parameter (default to 50% if not provided)
|
||||
DataCalc() ;
|
||||
break ;
|
||||
case _Triangle_:
|
||||
Funct = _Triangle_ ;
|
||||
RiseT = _val ; // Optional command line parameter (default to 50% if not provided)
|
||||
DataCalc() ;
|
||||
break ;
|
||||
}
|
||||
strcat (_Result.Txt,StatusString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DAC::Bump(int _type, int _dirn) {
|
||||
// Multi-purpose routine to bump various DAC operating values.
|
||||
// Parameters...
|
||||
// _type = operating value to be bumped (frequency, phase, level, sine, square, triangle, time)
|
||||
// _dirn = bump direction for the designated parameter (up, down)
|
||||
if (_type == _Freq_) {
|
||||
if ((Freq*Range==0) && (_dirn==_Down)) { // Attempt to bump below lower limit
|
||||
sprintf(RetStr,"Channel %c: Error - Minimum Frequency\n",name);
|
||||
strcat(_Result.Txt, RetStr);
|
||||
return 0;
|
||||
}
|
||||
// // TBD - remove hardcoded Max frequency
|
||||
else if ((Freq*Range==1000000) && (_dirn==_Up)) { // Attempt to bump above upper limit
|
||||
sprintf(RetStr,"Channel %c: Error - Maximum Frequency\n",name);
|
||||
strcat(_Result.Txt, RetStr);
|
||||
return 0;
|
||||
} else { // Not at max or min value...
|
||||
Freq += _dirn ; // ... bump
|
||||
if ((Freq == 1000) && (_dirn == _Up)) { // Range transition point
|
||||
Freq = 1 ; // Reset count
|
||||
if (Range == 1) Range = 1000 ; // either Hz=>KHz
|
||||
else if (Range == 1000) Range = 1000000 ; // or KHz=>MHz
|
||||
}
|
||||
if ((Freq==0) && (Range!=1) && (_dirn==_Down)) { // Range transition point
|
||||
Freq = 999 ; // Reset count
|
||||
if (Range == 1000) Range = 1 ; // either KHz=>Hz
|
||||
else if (Range == 1000000) Range = 1000 ; // or MHz=>KHz
|
||||
}
|
||||
_Result.Val = Freq ; // Grab value for SPI display
|
||||
DACspeed(Freq * Range) ; }
|
||||
}
|
||||
if (_type == _Phase_) {
|
||||
Phase += _dirn ;
|
||||
if (Phase == 360) Phase = 0 ; // Top Endwrap
|
||||
if (Phase < 0 ) Phase = 359 ; // Bottom Endwrap
|
||||
_Result.Val = Phase ; // Grab value for SPI display
|
||||
DataCalc(); } // Update Bitmap data to include new DAC phase
|
||||
if (_type == _Level_) {
|
||||
Level += _dirn ;
|
||||
if (Level > 100) { Level = 0 ; } // Top endwrap
|
||||
if (Level < 0 ) { Level = 100 ; } // Bottom endwrap
|
||||
_Result.Val = Level ; // Grab value for SPI display
|
||||
MCP41020_Write(SelectedChan, Level) ; // Control byte for the MCP42010 just happens to be the same value as the SelectedChan variable
|
||||
StatusString () ; } // Update the terminal session
|
||||
if (_type == _Square_) {
|
||||
DutyC += _dirn ;
|
||||
if (DutyC > 100) { DutyC = 0 ; } // Top endwrap
|
||||
if (DutyC < 0 ) { DutyC = 100 ; } // Bottom endwrap
|
||||
_Result.Val = DutyC ; // Grab value for SPI display
|
||||
DataCalc(); } // Update Bitmap with new Duty Cycle value
|
||||
if (_type == _Triangle_) {
|
||||
RiseT += _dirn ;
|
||||
if (RiseT > 100) { RiseT = 0 ; } // Top endwrap
|
||||
if (RiseT < 0 ) { RiseT = 100 ; } // Bottom endwrap
|
||||
_Result.Val = RiseT ; // Grab value for SPI display
|
||||
DataCalc(); } // Update Bitmap with new Duty Cycle value
|
||||
if (_type == _Sine_) {
|
||||
Harm += _dirn ;
|
||||
if (Harm > 10) { Harm = 0 ; } // Top endwrap
|
||||
if (Harm < 0 ) { Harm = 9 ; } // Bottom endwrap
|
||||
_Result.Val = Harm ; // Grab value for SPI display
|
||||
DataCalc(); } // Update Bitmap with new Sine harmonic value
|
||||
strcat (_Result.Txt,StatusString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DAC::DACspeed(int _frequency) {
|
||||
// If DAC_div exceeds 2^16 (65,536), the registers wrap around, and the State Machine clock will be incorrect.
|
||||
// A slow version of the DAC State Machine is used for frequencies below 17Hz, allowing the value of DAC_div to
|
||||
// be kept within the working range.
|
||||
float DAC_freq = _frequency * BitMapSize; // Target frequency...
|
||||
DAC_div = 2 * (float)clock_get_hz(clk_sys) / DAC_freq; // ...calculate the PIO clock divider required for the given Target frequency
|
||||
float Fout = 2 * (float)clock_get_hz(clk_sys) / (BitMapSize * DAC_div); // Actual output frequency
|
||||
if (_frequency >= 34) { // Fast DAC ( Frequency range from 34Hz to 999Khz )
|
||||
SM_WrapTop = SM_WrapBot ; // SM program memory = 1 op-code
|
||||
pio_sm_set_wrap (pio, StateMachine, SM_WrapBot, SM_WrapTop) ; // Fast loop (1 clock cycle)
|
||||
// If the previous frequency was < 33Hz, we will have just shrunk the assembler from 4 op-codes down to 1.
|
||||
// This leaves the State Machine program counter pointing outside of the new WRAP statement, which crashes the SM.
|
||||
// To avoid this, we need to also reset the State Machine program counter...
|
||||
pio->sm[StateMachine].instr = SM_WrapBot ; // Reset State Machine PC to start of code
|
||||
pio_sm_set_clkdiv(pio, StateMachine, DAC_div); // Set the State Machine clock
|
||||
} else { // Slow DAC ( 1Hz=>33Hz )
|
||||
DAC_div = DAC_div / 64; // Adjust DAC_div to keep within useable range
|
||||
DAC_freq = DAC_freq * 64;
|
||||
SM_WrapTop = SM_WrapBot + 3 ; // SM program memory = 4 op-codes
|
||||
pio_sm_set_wrap (pio, StateMachine, SM_WrapBot, SM_WrapTop) ; // slow loop (64 clock cycles)
|
||||
// If the previous frequency was >= 34Hz, we will have just expanded the assembler code from 1 op-code up to 4.
|
||||
// The State Machine program counter will still be pointing to an op-code within the new WRAP statement, so will not crash.
|
||||
pio_sm_set_clkdiv(pio, StateMachine, DAC_div); // Set the State Machine clock speed
|
||||
}
|
||||
}
|
||||
|
||||
void DAC::DataCalc() {
|
||||
// Calculate the bitmap for the various waveform outputs...
|
||||
int i, j, v_offset = BitMapSize/2 - 1; // Shift sine waves up above X axis
|
||||
int _phase;
|
||||
float a,b,x1,x2,g1,g2;
|
||||
|
||||
// Scale the phase shift to match data size...
|
||||
_phase = Phase * BitMapSize / 360 ; // Input range: 0 -> 360 (degrees)
|
||||
// Output range: 0 -> 255 (bytes)
|
||||
switch (Funct) {
|
||||
case _Sine_:
|
||||
Harm = Harm % 11; // Sine harmonics cycles after 10
|
||||
for (i=0; i<BitMapSize; i++) {
|
||||
// Add the phase offset and wrap data beyond buffer end back to the buffer start...
|
||||
j = ( i + _phase ) % BitMapSize; // Horizontal index
|
||||
a = v_offset * sin((float)_2Pi*i / (float)BitMapSize); // Fundamental frequency...
|
||||
if (Harm >= 1) { a += v_offset/3 * sin((float)_2Pi*3*i / (float)BitMapSize); } // Add 3rd harmonic
|
||||
if (Harm >= 2) { a += v_offset/5 * sin((float)_2Pi*5*i / (float)BitMapSize); } // Add 5th harmonic
|
||||
if (Harm >= 3) { a += v_offset/7 * sin((float)_2Pi*7*i / (float)BitMapSize); } // Add 7th harmonic
|
||||
if (Harm >= 4) { a += v_offset/9 * sin((float)_2Pi*9*i / (float)BitMapSize); } // Add 9th harmonic
|
||||
if (Harm >= 5) { a += v_offset/11 * sin((float)_2Pi*11*i / (float)BitMapSize); } // Add 11th harmonic
|
||||
if (Harm >= 6) { a += v_offset/13 * sin((float)_2Pi*13*i / (float)BitMapSize); } // Add 13th harmonic
|
||||
if (Harm >= 7) { a += v_offset/15 * sin((float)_2Pi*15*i / (float)BitMapSize); } // Add 15th harmonic
|
||||
if (Harm >= 8) { a += v_offset/17 * sin((float)_2Pi*17*i / (float)BitMapSize); } // Add 17th harmonic
|
||||
if (Harm >= 9) { a += v_offset/19 * sin((float)_2Pi*19*i / (float)BitMapSize); } // Add 19th harmonic
|
||||
if (Harm >= 10) { a += v_offset/20 * sin((float)_2Pi*20*i / (float)BitMapSize); } // Add 21st harmonic
|
||||
DAC_data[j] = (int)(a)+v_offset; // Sum all harmonics and add vertical offset
|
||||
}
|
||||
break;
|
||||
case _Square_:
|
||||
b = DutyC * BitMapSize / 100; // Convert % to value
|
||||
for (i=0; i<BitMapSize; i++) {
|
||||
j = ( i + _phase ) % BitMapSize; // Horizontal index
|
||||
if (b <= i) { DAC_data[j] = 0; } // First section low
|
||||
else { DAC_data[j] = 255; } // Second section high
|
||||
}
|
||||
break;
|
||||
case _Triangle_:
|
||||
x1 = (RiseT * BitMapSize / 100) -1; // Number of data points to peak
|
||||
x2 = BitMapSize - x1; // Number of data points after peak
|
||||
g1 = (BitMapSize - 1) / x1; // Rising gradient (Max val = BitMapSize -1)
|
||||
g2 = (BitMapSize - 1) / x2; // Falling gradient (Max val = BitMapSize -1)
|
||||
for (i=0; i<BitMapSize; i++) {
|
||||
j = ( i + _phase ) % BitMapSize; // Horizontal index
|
||||
if (i <= x1) { DAC_data[j] = i * g1; } // Rising section of waveform...
|
||||
if (i > x1) { DAC_data[j] = (BitMapSize - 1) - ((i - x1) * g2); } // Falling section of waveform
|
||||
}
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
// The following function is not really a member of the DAC class, as it operates across the two DAC objects simultaneously.
|
||||
// Code is included here for the purposes of clarity.
|
||||
void PhaseLock( DAC DACobj[2] ) {
|
||||
// Phase lock the two DAC channels...
|
||||
// Parameter...
|
||||
// DACobj[2] = Array containing the two DAC objects.
|
||||
|
||||
// Disable the Ctrl channels...
|
||||
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_A].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_B].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
|
||||
// Abort the data channels...
|
||||
dma_channel_abort(DACobj[_DAC_A].data_chan);
|
||||
dma_channel_abort(DACobj[_DAC_B].data_chan);
|
||||
|
||||
// Reset the data transfer DMA's to the start of the data Bitmap...
|
||||
dma_channel_set_read_addr(DACobj[_DAC_A].data_chan, &DACobj[_DAC_A].DAC_data[0], false);
|
||||
dma_channel_set_read_addr(DACobj[_DAC_B].data_chan, &DACobj[_DAC_B].DAC_data[0], false);
|
||||
|
||||
// Re-enable the Ctrl channels (doesn't restart data transfer)...
|
||||
hw_set_bits(&dma_hw->ch[DACobj[_DAC_A].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
hw_set_bits(&dma_hw->ch[DACobj[_DAC_B].ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
|
||||
|
||||
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "DAC.pio.h"
|
||||
#include "SPI_Utils.h"
|
||||
|
||||
#define BitMapSize 256
|
||||
#define _Up 1
|
||||
#define _Down -1
|
||||
#define _Sine_ 0
|
||||
#define _Square_ 1
|
||||
#define _Triangle_ 2
|
||||
//#define _Time_ 3
|
||||
#define _Freq_ 6
|
||||
#define _Level_ 7
|
||||
|
||||
// Custom data type used to store both text and numeric data results.
|
||||
// Txt value is the string to be passed to the terminal display.
|
||||
// Num value is passed to a 3 digit numeric display module using an SPI connection.
|
||||
// Note: defined outside of class, so can be re-used by other modules.
|
||||
struct Result {
|
||||
char Txt[3000];
|
||||
int Val; };
|
||||
|
||||
extern unsigned short DAC_channel_mask;
|
||||
extern const uint32_t transfer_count;
|
||||
extern int MarginCount, SelectedChan, Value;
|
||||
extern Result _Result;
|
||||
|
||||
class DAC {
|
||||
public:
|
||||
PIO pio;
|
||||
unsigned short DAC_data[BitMapSize] __attribute__ ((aligned(2048))) ; // Align DAC data (2048d = 0800h)
|
||||
// uint8_t DAC_data[BitMapSize] __attribute__ ((aligned(2048))) ; // Align DAC data (2048d = 0800h)
|
||||
int Funct, Range, PIOnum, Level, Freq, Phase, DutyC, Harm, RiseT ;
|
||||
uint8_t StateMachine, ctrl_chan, data_chan, GPIO, SM_WrapBot, SM_WrapTop ;
|
||||
float DAC_div ;
|
||||
char name;
|
||||
|
||||
DAC(char _name, PIO _pio, uint8_t _GPIO);
|
||||
char* StatusString(); // TBD - is this the same as RetStr ???
|
||||
int Set(int _type, int _val);
|
||||
int Bump(int _type, int _dirn);
|
||||
void DACspeed(int _frequency);
|
||||
void DataCalc();
|
||||
|
||||
private:
|
||||
const float _2Pi = 6.283; // 2*Pi
|
||||
char RetStr[300];
|
||||
};
|
||||
|
||||
void PhaseLock(DAC DACobj[2]); // Not a member of the class
|
|
@ -0,0 +1,115 @@
|
|||
#include "Demo.h"
|
||||
|
||||
bool SweepParm (DAC DACobj[], int _parm, int _start, int _stop, int _speed, int _pause) {
|
||||
// Returns true when complete, returns false if 'Q' or 'q' pressed.
|
||||
char c ;
|
||||
int i=_start;
|
||||
int step, count ;
|
||||
if (_start<=_stop) { step=1 ; } // Increment
|
||||
else { step=-1 ; } // Decrement
|
||||
while (true) {
|
||||
count=0 ;
|
||||
i=i+step ;
|
||||
if (SelectedChan & 0b01) DACobj[_DAC_A].Set(_parm,i) ; // Set frequency, display status
|
||||
if (SelectedChan & 0b10) DACobj[_DAC_B].Set(_parm,i) ;
|
||||
printf(_Result.Txt) ; // Update terminal
|
||||
_Result.Txt[0] = '\0' ; // Reset the string variable
|
||||
SPI_Display_Write(i) ;
|
||||
if ((i==_start)or(i==_stop)) break ; // End of sweep
|
||||
// Loop to create a short pause between steps of the sweep.
|
||||
// Note: keyboard input is still scanned providing immediate exit on key press
|
||||
while (count<_speed) {
|
||||
c=getchar_timeout_us(0);
|
||||
count++;
|
||||
sleep_ms(1) ;
|
||||
if ((c=='q') or (c=='Q')) {
|
||||
while (c!=254) {
|
||||
c=getchar_timeout_us(0) ; // wait for key release
|
||||
sleep_ms(1) ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
} // Falls through here when sweep has completed.
|
||||
// Second loop creates a longer pause at the end of each sweep.
|
||||
// Note: keyboard input is still scanned providing immediate exit on key press
|
||||
count=0 ;
|
||||
while (count<_pause) {
|
||||
c=getchar_timeout_us(0);
|
||||
count++;
|
||||
sleep_ms(1) ;
|
||||
if ((c=='q') or (c=='Q')) {
|
||||
while (c!=254) {
|
||||
c=getchar_timeout_us(0) ; // wait for key release
|
||||
sleep_ms(1) ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
void Demo_01 (DAC DACobj[]) {
|
||||
// Demo 01: Standard waveforms
|
||||
// Sine with varying harmonics
|
||||
// Triangle with varying rise times
|
||||
// Square wave with varying duty cycle
|
||||
// Frequency and Level of the Demo can be set through the Function Generator interface.
|
||||
int speed=5 ; // Pause between steps (ms)
|
||||
int pause=1000 ; // Pause between stages (ms)
|
||||
int Maxlevel ; // Max level (amplitude) of the DAC channels
|
||||
// Set Maxlevel to the largest existing DAC level. This allows us to use the Function Generator mode to scale the
|
||||
// vertical output to fit the oscilloscope screen. IF we re-use this value, we ensure the demo will also fit the oscilloscope
|
||||
// vertical screen size .
|
||||
if (DACobj[_DAC_A].Level<DACobj[_DAC_B].Level) Maxlevel=DACobj[_DAC_B].Level ; // Bigger of the two values
|
||||
else Maxlevel=DACobj[_DAC_A].Level ;
|
||||
SelectedChan=0b011 ; // Select both channels
|
||||
SetVal(DACobj,_Level_,0) ; // Set Output level 0
|
||||
_Result.Txt[0] = '\0' ; // String also used as a flag, so needs to be cleared
|
||||
while (true) {
|
||||
SetVal(DACobj,_Triangle_,50) ; // Set Triangle wave, 50% rise time
|
||||
if (!SweepParm(DACobj,_Level_,0,Maxlevel,speed,pause)) break ; // Sweep up - exit on keypess
|
||||
if (!SweepParm(DACobj,_Triangle_,50,0,speed,pause)) break ; // Rise time -> 0 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Triangle_,0,100,speed,pause)) break ; // Rise time -> 100 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Triangle_,100,50,speed,pause)) break ; // Rise time -> 50 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Level_,Maxlevel,0,speed,pause)) break ; // Sweep down - exit on keypress
|
||||
SetVal(DACobj,_Sine_,0) ; // Set Sine wave, no harmonics
|
||||
if (!SweepParm(DACobj,_Level_,0,Maxlevel,speed,pause)) break ; // Sweep up - exit on keypess
|
||||
if (!SweepParm(DACobj,_Sine_,0,5,pause,pause)) break ; // Harmonic -> 5 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Sine_,5,0,pause,pause)) break ; // Harmonic -> 0 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Level_,Maxlevel,0,speed,pause)) break ; // Sweep down - exit on keypress
|
||||
SetVal(DACobj,_Square_,50) ; // Set Square wave, 50% duty cycle
|
||||
if (!SweepParm(DACobj,_Level_,0,Maxlevel,speed,pause)) break ; // Sweep up - exit on keypess
|
||||
if (!SweepParm(DACobj,_Square_,50,0,speed,pause)) break ; // Duty cycle -> 0 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Square_,0,100,speed,pause)) break ; // Duty cycle -> 100 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Square_,100,50,speed,pause)) break ; // Duty cycle -> 50 - exit on keypress
|
||||
if (!SweepParm(DACobj,_Level_,Maxlevel,0,speed,pause)) break ; // Sweep down - exit on keypress
|
||||
}
|
||||
sprintf(_Result.Txt,"%sQuit demo #1\n",MarginVW); // Prevents error message on return
|
||||
}
|
||||
|
||||
void Demo_02 (DAC DACobj[]) {
|
||||
// Demo 02: Lazy Lissajous
|
||||
int speed=5 ; // Pause between steps (ms)
|
||||
int pause=0 ; // Pause between stages (ms)
|
||||
_Result.Txt[0] = '\0' ; // String also used as a flag, so needs to be cleared
|
||||
SelectedChan=0b001 ; // Select channel A
|
||||
SetVal(DACobj,_Freq_,100) ; // Set 100Hz
|
||||
while (true) {
|
||||
SetVal(DACobj,_Sine_,0) ; // Set Sine wave, no harmonics
|
||||
SelectedChan=0b010 ; // Select channel B
|
||||
SetVal(DACobj,_Freq_,100) ; // Set 100Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
SetVal(DACobj,_Freq_,200) ; // Set 200Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
SetVal(DACobj,_Freq_,300) ; // Set 300Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
SetVal(DACobj,_Freq_,400) ; // Set 400Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
SetVal(DACobj,_Freq_,500) ; // Set 500Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
SetVal(DACobj,_Freq_,600) ; // Set 600Hz
|
||||
if (!SweepParm(DACobj,_Phase_,0,1400,speed,pause)) break ; // Sweep phase - exit on keypess
|
||||
}
|
||||
sprintf(_Result.Txt,"%sQuit demo #2\n",MarginVW); // Prevents error message on return
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "DAC_Class.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
extern int Parm[] ;
|
||||
extern int SetVal(DAC DACobj[], int _Parm, int _Value) ;
|
||||
extern char MarginVW[], Margin[], inStr[] ;
|
||||
|
||||
bool SweepParm (DAC DACobj[], int _parm, int _start, int _stop, int _speed, int pause) ;
|
||||
void Demo_01 (DAC DACobj[]) ;
|
||||
void Demo_02 (DAC DACobj[]) ;
|
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
//#define NewHardware // Comment/Uncomment to select active GPIO ports
|
||||
|
||||
#ifdef NewHardware
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define GPIO connections for Pico (new hardware)...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Phase lock:
|
||||
// Read/Write through serial port does not use DMA channels. This removes most DAC channels jitter at
|
||||
// high frequencies.
|
||||
// 1 Hz => 900 KHz - Phase sync stable
|
||||
// 900 KHz => 1 MHz - Phase sync usable - random drifting easily corrected by hitting 'return'
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define SPI_PORT spi1 // Using SPI port 1
|
||||
// ┌──────────┬───────────────┬─────────────┐────────────────┐
|
||||
// │ PGA2040 │ Connection │ MCP41010 │ Display module │
|
||||
// ├──────────┼───────────────┼─────────────┤────────────────┤
|
||||
#define PIN_RX 12 // │ GPIO 12 │ SPI1 RX │ (unused) │ (unused) │
|
||||
#define Display_CS 26 // │ GPIO 17 │ Chip select │ (unused) │ SS1 (white) │
|
||||
#define PIN_CLK 10 // │ GPIO 10 │ SPI1 Clock │ SCK (Pin 2) │ SCK (blue) │
|
||||
#define PIN_TX 11 // │ GPIO 11 │ SPI1 TX │ SI (Pin 3) │ SDI (green) │
|
||||
#define Level_CS 22 // │ GPIO 22 │ Chip select │ CS (Pin 1) │ (unused) │
|
||||
// └──────────┴───────────────┴─────────────┘────────────────┘
|
||||
#define DAC_A_Start 2 // First GPIO port used by DAC A
|
||||
#define DAC_B_Start 14 // First GPIO port used by DAC B
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#else
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define GPIO connections for Pico (Module)...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Phase lock:
|
||||
// Read/Write through USB serial port requires DMA channel usage. This makes the DAC channels jitter at
|
||||
// high frequencies and causes phase sync issues.
|
||||
// 1 Hz => 250 KHz - Phase sync stable
|
||||
// 250 KHz => 750 KHz - Phase sync usable - some drifting noticable when using USB serial input
|
||||
// 750 KHz => 1 MHz - Phase sync unusable - random drifting
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Note: 1) The SPI Port only works through specific pins, so these connections are defined first.
|
||||
// 2) Pin assignments prevent the use of the UART for this configuration.
|
||||
// SPI Port connections...
|
||||
#define SPI_PORT spi0 // Using SPI port 0
|
||||
// ┌──────────┬───────────────┬─────────────┐────────────────┐
|
||||
// │ PGA2040 │ Connection │ MCP41010 │ Display module │
|
||||
// ├──────────┼───────────────┼─────────────┤────────────────┤
|
||||
#define PIN_RX 16 // │ GPIO 16 │ SPI0 RX │ (unused) │ (unused) │
|
||||
#define Display_CS 17 // │ GPIO 17 │ Chip select │ (unused) │ SS1 (white) │
|
||||
#define PIN_CLK 18 // │ GPIO 18 │ SPI0 Clock │ SCK (Pin 2) │ SCK (blue) │
|
||||
#define PIN_TX 19 // │ GPIO 19 │ SPI0 TX │ SI (Pin 3) │ SDI (green) │
|
||||
#define Level_CS 20 // │ GPIO 20 │ Chip select │ CS (Pin 1) │ (unused) │
|
||||
// └──────────┴───────────────┴─────────────┘────────────────┘
|
||||
#define DAC_A_Start 0 // First GPIO port used by DAC A
|
||||
#define DAC_B_Start 8 // First GPIO port used by DAC B
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
// Definitions common to either hardware...
|
||||
#define _DAC_A 0 // DAC channel alias
|
||||
#define _DAC_B 1 // DAC channel alias
|
||||
#define _Funct_ 2
|
||||
#define _Phase_ 3
|
||||
#define _Duty_ 4
|
||||
#define _Range_ 5
|
||||
#define _Harmonic_ 10
|
||||
#define _PIOnum_ pio0 // Code will work equally well on either pio0 or pio1
|
||||
#define eof 255 // EOF in stdio.h -is -1, but getchar returns int 255 to avoid blocking
|
||||
#define CR 13
|
||||
#define MWidth 12 // Width of terminal command margin (in columns)
|
||||
|
||||
// Define clock speed...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//#define SysClock 125 // System clock for 0.488 MHz DAC output (Pico default)
|
||||
//#define SysClock 250 // System clock x 2 for 0.977 MHz DAC output
|
||||
#define SysClock 280 // Overclock for 1.000 MHz DAC output
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,42 @@
|
|||
#include "SPI_Utils.h"
|
||||
|
||||
void SPI_Init(int _clk, int _tx) {
|
||||
// Initialise the SPI bus hardawre...
|
||||
spi_init(SPI_PORT, 500000); // Set SPI bus at 0.5MHz...
|
||||
gpio_set_dir(_clk, GPIO_OUT) ; // Initialise remaining SPI connections...
|
||||
gpio_set_dir(_tx, GPIO_OUT) ;
|
||||
gpio_set_function(_clk, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_tx, GPIO_FUNC_SPI);
|
||||
}
|
||||
|
||||
void cs_select(int _gpio) {
|
||||
asm volatile("nop \n nop \n nop");
|
||||
gpio_put(_gpio, 0); // Active low
|
||||
asm volatile("nop \n nop \n nop");
|
||||
}
|
||||
|
||||
void cs_deselect(int _gpio) {
|
||||
asm volatile("nop \n nop \n nop");
|
||||
gpio_put(_gpio, 1); // Inactive high
|
||||
asm volatile("nop \n nop \n nop");
|
||||
}
|
||||
|
||||
void SPI_Display_Write(int _data) {
|
||||
uint8_t buff[2];
|
||||
buff[0] = _data / 256; // MSB data
|
||||
buff[1] = _data % 256; // LSB data
|
||||
cs_select(Display_CS);
|
||||
spi_write_blocking(SPI_PORT, buff, 2);
|
||||
cs_deselect(Display_CS);
|
||||
}
|
||||
|
||||
void MCP41020_Write (uint8_t _ctrl, uint8_t _data) {
|
||||
// Parameters: _ctrl - channel to write to ( 0b01=A, 0b10=B, 0b11=Both )
|
||||
// _data - value to be written ( 0-255 )
|
||||
uint8_t buff[2];
|
||||
buff[0] = _ctrl | 0x10 ; // Set control bit to Write data
|
||||
buff[1] = _data * 2.55 ; // Scale data byte (100%->255)
|
||||
cs_select(Level_CS) ; // Transmit data to Digi-Pot
|
||||
spi_write_blocking(SPI_PORT, buff, 2) ;
|
||||
cs_deselect(Level_CS) ;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "GPIO+Definitions.h"
|
||||
|
||||
void SPI_Init(int _clk, int _tx);
|
||||
void cs_select(int _gpio);
|
||||
void cs_deselect(int _gpio);
|
||||
void SPI_Display_Write(int _data);
|
||||
void MCP41020_Write(uint8_t _ctrl, uint8_t _data);
|
|
@ -0,0 +1,84 @@
|
|||
# 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 ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
|
||||
endif ()
|
||||
|
||||
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
|
||||
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
|
||||
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")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for 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 ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
)
|
||||
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})
|
Ładowanie…
Reference in New Issue