master
Tony 2023-08-25 13:42:33 +01:00
rodzic bd55c22466
commit ae8697f44a
3 zmienionych plików z 314 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,22 @@
add_executable(Clock)
# pull in common dependencies
target_sources(Clock PRIVATE Clock.cpp)
# pull in common dependencies and additional spi hardware support
target_link_libraries(Clock PRIVATE
pico_stdlib
hardware_pio
hardware_dma
hardware_spi
)
# enable usb output, disable uart output
pico_enable_stdio_usb(Clock 1)
pico_enable_stdio_uart(Clock 0)
# create map/bin/hex file etc.
pico_add_extra_outputs(Clock)
# add url via pico_set_program_url
example_auto_set_url(Clock)

237
Clock/Clock.cpp 100644
Wyświetl plik

@ -0,0 +1,237 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/spi.h"
#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/gpio.h" // Required for manually toggling GPIO pins (clock)
#define eof 255 // EOF in stdio.h -is -1, but getchar returns int 255 to avoid blocking
#define CR 13
#define BitMapSize 256 // Match X to Y resolution
#define MWidth 10 // Width of terminal command margin (in columns)
#define SysClock 125 // System clock (Pico default)
//#define SysClock 250 // System clock x 2 (Overclock)
// Data for clock face generated by Excel spreadsheet...
uint8_t FaceX[] = {235,239,243,247,251,255,255,254,254,254,254,254,254,254,253,253,253,252,252,251,251,250,250,249,248,248,247,246,245,244,244,243,242,241,240,239,221,224,227,231,234,238,236,235,234,233,232,230,229,228,226,225,224,222,221,219,218,216,214,213,211,209,208,206,204,203,201,199,197,195,193,182,184,186,188,190,191,190,188,186,184,182,180,178,176,174,172,170,167,165,163,161,159,157,155,153,150,148,146,144,142,139,137,135,133,131,128,128,128,128,128,128,126,124,122,120,117,115,113,111,109,107,104,102,100,98,96,94,92,90,87,85,83,81,79,77,75,73,71,69,67,75,73,71,69,67,65,64,62,60,58,56,54,53,51,49,47,46,44,43,41,39,38,36,35,33,32,31,29,28,27,25,24,23,22,20,36,33,30,26,23,19,18,17,16,15,14,13,12,12,11,10,9,9,8,7,7,6,6,5,5,4,4,4,3,3,3,3,3,3,2,22,18,14,10,6,2,2,3,3,3,3,3,3,4,4,4,5,5,6,6,7,7,8,9,9,10,11,12,12,13,14,15,16,17,18,36,33,30,26,23,19,20,22,23,24,25,27,28,29,31,32,33,35,36,38,39,41,43,44,46,47,49,51,53,54,56,58,60,62,64,75,73,71,69,67,65,67,69,71,73,75,77,79,81,83,85,87,90,92,94,96,98,100,102,
104,107,109,111,113,115,117,120,122,124,126,128,128,128,128,128,128,131,133,135,137,139,142,144,146,148,150,153,155,157,159,161,163,165,167,170,172,174,176,178,180,182,184,186,188,190,182,184,186,188,190,191,193,195,197,199,201,203,204,206,208,209,211,213,214,216,218,219,221,222,224,225,226,228,229,230,232,233,234,235,236,221,224,227,231,234,238,239,240,241,242,243,244,244,245,246,247,248,248,249,250,250,251,251,252,252,253,253,253,254,254,254,254,254,254,254} ;
uint8_t FaceY[] = {128,128,128,128,128,128,128,126,124,122,120,117,115,113,111,109,107,104,102,100,98,96,94,92,90,87,85,83,81,79,77,75,73,71,69,67,75,73,71,69,67,65,64,62,60,58,56,54,53,51,49,47,46,44,43,41,39,38,36,35,33,32,31,29,28,27,25,24,23,22,20,36,33,30,26,23,19,18,17,16,15,14,13,12,12,11,10,9,9,8,7,7,6,6,5,5,4,4,4,3,3,3,3,3,3,2,22,18,14,10,6,2,2,3,3,3,3,3,3,4,4,4,5,5,6,6,7,7,8,9,9,10,11,12,12,13,14,15,16,17,18,36,33,30,26,23,19,20,22,23,24,25,27,28,29,31,32,33,35,36,38,39,41,43,44,46,47,49,51,53,54,56,58,60,62,64,75,73,71,69,67,65,67,69,71,73,75,77,79,81,83,85,87,90,92,94,96,98,100,102,104,107,109,111,113,115,117,120,122,124,126,128,128,128,128,128,128,131,133,135,137,139,142,144,146,148,150,153,155,157,159,161,163,165,167,170,172,174,176,178,180,182,184,186,188,190,182,184,186,188,190,191,193,195,197,199,201,203,204,206,208,209,211,213,214,216,218,219,221,222,224,225,226,228,229,230,232,233,234,235,236,221,224,227,231,234,238,239,240,241,242,243,244,244,245,246,247,248,248,249,250,250,251,251,252,
252,253,253,253,254,254,254,254,254,254,254,235,239,243,247,251,255,254,254,254,254,254,254,254,253,253,253,252,252,251,251,250,250,249,248,248,247,246,245,244,244,243,242,241,240,239,221,224,227,231,234,238,236,235,234,233,232,230,229,228,226,225,224,222,221,219,218,216,214,213,211,209,208,206,204,203,201,199,197,195,193,182,184,186,188,190,191,190,188,186,184,182,180,178,176,174,172,170,167,165,163,161,159,157,155,153,150,148,146,144,142,139,137,135,133,131} ;
// (Number of pixels: 421)
// Store clock hands co-ordinates...
uint8_t HandsX[192] = {} ; // Each hand requires 64 bytes - 3x64=192
uint8_t HandsY[192] = {} ;
int Hours=0, Mins=0, Secs=0, Angle, StartX, StartY, Radius ;
float Radians ;
int tmp ; // Debug and general use
char MarginFW[MWidth+1], MarginVW[MWidth+1] ; // Fixed Width & Variable Width strings to create a fixed margin
//unsigned short DAC_channel_mask = 0 ; // Binary mask to simultaneously start all DMA channels
//const uint32_t transfer_count = BitMapSize ; // Number of DMA transfers per event
//const float _2Pi = 6.283; // 2*Pi
int c, i, ParmCnt = 0, Parm[4], WaveForm_Type ;
//int SelectedChan, c, i = 0, dirn = 1, result ;
int MarginCount = 0 ; // Manual count of characters written to terminal - required to maintain margins
//float MaxDACfreq ;
char inStr[15], outStr[1000], ResultStr[3000] ;
bool Repeating_Timer_Callback(struct repeating_timer *t) {
int i, steps=64, MidX=128, MidY=128 ;
// Bump the time...
if ((++Secs)>59) Secs=0 ; // Always bump seconds
if (Secs==0) { if ((++Mins)>59 ) Mins=0 ; } // Bump minutes when seconds = 0
if ((Mins==0) && (Secs==0)) { if ((++Hours)>12) Hours=0 ; } // Bump hours when minutes and seconds = 0
// Calculate seconds hand...
i=0, Radius=127 ;
Angle=90-(Secs*6) ; // Angle in degrees
Radians=Angle*3.14159/180 ; // Angle in radians
StartX=Radius*cos(Radians)+MidX ;
StartY=Radius*sin(Radians)+MidY ;
while(i<steps) { HandsX[i]=StartX+i*(MidX-StartX)/steps ;
HandsY[i]=StartY+i*(MidY-StartY)/steps ;
i++ ; }
// Calculate minutes hand...
Radius=95 ;
Angle=90-(Mins*6) ; // Angle in degrees
Radians=Angle*3.14159/180 ; // Angle in radians
StartX=Radius*cos(Radians)+MidX ;
StartY=Radius*sin(Radians)+MidY ;
i=0 ;
while(i<steps) { HandsX[i+steps]=StartX+i*(MidX-StartX)/steps ;
HandsY[i+steps]=StartY+i*(MidY-StartY)/steps ;
i++ ; }
// Calculate hours hand...
// Note: Hours hand progresses between hours in 5 partial increments, each measuring 12 minutes.
// Each 12 minute increment adds an additional 6 degrees of rotation to the hours hand.
Radius=64 ;
Angle=5*(90-((Hours*6)+(Mins/2)%5)) ; // Angle in degrees
//Angle=5*(90-((6*(Hours))+(Mins/12))%5) ; // TBD - does this work ? is it clearer ?
Radians=Angle*3.14159/180 ; // Angle in radians
StartX=Radius*cos(Radians)+MidX ;
StartY=Radius*sin(Radians)+MidY ;
i=0 ;
while(i<steps) { HandsX[i+2*steps]=StartX+i*(MidX-StartX)/steps ;
HandsY[i+2*steps]=StartY+i*(MidY-StartY)/steps ;
i++ ; }
// printf("%s%d:%d:%d - %d\n",MarginFW,Hours,Mins,Secs,tmp) ; // Debug
return true;
}
void VerText () {
// Print version info aligned to current margin settings...
tmp = strlen(inStr) ; // Get number of command line characters
if (tmp != 0) tmp ++ ; // If there are characters, Bump to also allow for cursor
MarginVW[MWidth - tmp] = '\0' ; // Calculate padding required for command characters and cursor
sprintf(ResultStr, "%s|-------------------------|\n"
"%s| Analog Clock Simulator |\n"
"%s| Version 1.0.0 |\n"
"%s| 25th August 2023 |\n"
"%s|-------------------------|\n",
MarginVW, MarginFW, MarginFW, MarginFW, MarginFW ) ;
}
void HlpText () {
// Print Help text aligned to current margin settings...
// Note: Following string requires '%%%%' to print '%'
// HelpText string is copied to outStr using sprintf - this reduces '%%%%' to '%%'
// outStr is sent to terminal using printf - this reduces '%%' to '%'
tmp = strlen(inStr) ; // Get number of command line characters
if (tmp != 0) tmp ++ ; // If there are characters, Bump to also allow for cursor
MarginVW[MWidth - tmp] = '\0' ; // Calculate padding required for command characters and cursor
sprintf(ResultStr, "%sHelp...\n"
"%s? - Help\n"
"%sV - Version\n"
"%s<A/B/C>scnn,nn,nn - Set time Hours,Mins,Seconds\n"
"%swhere...\n"
"%s<A/B/C> = DAC channel A,B or Both\n"
"%snnn = Three digit numeric value\n",
MarginVW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW) ;
}
static inline 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");
}
static inline void cs_deselect(int _gpio) {
asm volatile("nop \n nop \n nop");
gpio_put(_gpio, 1);
asm volatile("nop \n nop \n nop");
}
static void getLine() {
char *pPos = (char *)inStr ; // Pointer to start of Global input string
int count = 0 ;
while(1) {
c = getchar();
if (c == eof || c == '\n' || c == '\r') break ; // Non blocking exit
putchar(c); // FullDuplex echo
*pPos++ = c ; // Bump pointer, store character
count ++ ;
}
*pPos = '\0' ;
MarginCount += count ; // Track number of characters on current line
return ;
}
int main() {
set_sys_clock_khz(SysClock*1000, true) ; // Set Pico clock speed
stdio_init_all() ;
// Initialise GPIO ports for use with R-2R resistor network...
// (Setting Max slew rate and gpio drive strength keeps output linear at high frequencies)
for (int gpio = 0; gpio < 16; gpio++) {
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
gpio_set_slew_rate(gpio, GPIO_SLEW_RATE_FAST);
gpio_set_drive_strength(gpio, GPIO_DRIVE_STRENGTH_12MA);
}
struct repeating_timer timer;
add_repeating_timer_ms(-1000, Repeating_Timer_Callback, NULL, &timer) ;
memset(MarginFW,' ',MWidth) ; // Initialise Fixed Width margin...
MarginFW[MWidth] = '\0' ; // ... and terminate
memset(MarginVW,' ',MWidth) ; // Initialise Variable Width margin...
MarginVW[MWidth] = '\0' ; // ... and terminate
ResultStr[0] = '\0' ; // Reset string
while (!stdio_usb_connected()) { sleep_ms(100); } // Wait for USB connection...
// Send (optional) start-up messages to terminal...
VerText() ; // Version text
printf(ResultStr) ; // Update terminal
while(1) {
memset(MarginVW,' ',MWidth) ; // Re-initialise Variable Width margin...
MarginVW[MWidth] = '\0' ; // ... and terminate
ResultStr[0] = '\0' ; // Reset string
printf(">") ; // Command prompt
MarginCount = 1 ; // Reset count and bump for command prompt
// Clock display code...
gpio_clr_mask(0xff) ; // clear first 16 GPIO outputs
ResultStr[0] = '\0' ; // String also used as a flag, so needs to be cleared
while (ResultStr[0] == '\0') { // exit on keypress
// Draw the clock face...
for (int i=0; i<sizeof(FaceX); i++) {
gpio_put_masked(0x00ff,FaceX[i]) ; // Write data byte to DAC A
gpio_put_masked(0xff00,FaceY[i]<<8) ; // Write data byte to DAC B
sleep_us(2) ; // Pause for on-screen persistance
}
// Draw the clock hands...
for (i=0; i<192; i++) { // 3 hands @ 64 pixels each = 192
gpio_put_masked(0x00ff,HandsX[i]) ; // Write data byte to DAC A
gpio_put_masked(0xff00,HandsY[i]<<8) ; // Write data byte to DAC B
sleep_us(2) ; // Pause for on-screen persistance
}
// Check for console input...
c = getchar_timeout_us (0); // Non-blocking char input
if ((c=='S') or (c=='s')) { // Set time
MarginCount = 1 ; // Reset count and bump for command prompt
MarginVW[MWidth - MarginCount] = '\0' ; // Calculate padding required for command characters and cursor
printf("%sSet time (format HH:MM:SS)\n%s",MarginVW, MarginFW ) ;
getLine() ; // Get the console input
Parm[0]=0, Parm[1]=0, Parm[2]=0, Parm[3]=0 ; // Reset all command line parameters
i=0, ParmCnt=0 ; // Reset all command line counters
while (i<strlen(inStr) ) {
if (inStr[i]==':') { ParmCnt++ ; } // Next parameter
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
}
Hours=Parm[0]%24 ; Mins=Parm[1]%60 ; Secs=Parm[2]%60 ; // Set the time from parameters
printf("\n%sClock set to %02d:%02d:%02d\n>",MarginFW,Hours,Mins,Secs) ;
}
}
if (strlen(ResultStr) == 0) { // No result can only mean unrecognised command
strcpy(MarginVW,MarginFW) ; // Reset Variable Width margin
tmp = strlen(inStr) ;
if (tmp != 0) tmp ++ ; // Bump to allow for cursor character
MarginVW[MWidth - tmp] = '\0' ; // Calculate padding for input and cursor
sprintf(outStr,"%sUnknown command!\n", MarginVW) ; // Empty response buffer indicates command has not been recognised
}
else strcpy(outStr,ResultStr) ;
printf(outStr) ; // Update terminal
outStr[0] = '\0' ; // Clear (reset) the string variable
// strcpy(LastCmd, inStr) ; // Preserve last command
}
return 0;
}

Wyświetl plik

@ -0,0 +1,55 @@
{
"folders": [
{
"name": "sandpit",
"path": ".."
}
],
"settings": {
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}
}