Improved Phase Lock

master
Tony 2023-09-19 13:08:59 +01:00
rodzic 2f277b4448
commit 17c262526c
4 zmienionych plików z 207 dodań i 240 usunięć

Wyświetl plik

@ -31,6 +31,7 @@ void pio_DAC_program_init(PIO pio, uint sm, uint offset, uint start_pin) {
pio_sm_config c = pio_DAC_program_get_default_config(offset); // Define PIO Configuration structure
sm_config_set_out_pins(&c, start_pin, 8); // Configure pins to be targeted by the OUT (and MOV) commands
sm_config_set_out_shift(&c, true, true, 8); // Shift right, Autopull enabled, 6/8 bits
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // Set TX_FIFO to 8. Improves stability at high frequencies
pio_sm_init(pio, sm, offset, &c); // Load configuration and jump to start of the program
pio_sm_set_enabled(pio, sm, true);
}

Wyświetl plik

@ -1,3 +1,7 @@
// TBD: 1) SPI read connecton
// 2) Capacitors on op-amps
// 3) Issue with phase lock - red/writes to serial port affecting phase lock at high frequencies
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@ -9,7 +13,6 @@
#include "hardware/dma.h"
#include "blink.pio.h"
#include "DAC.pio.h"
#include "hardware/gpio.h" // Required for manually toggling GPIO pins (clock)
//////////////////////////////////////
@ -53,17 +56,25 @@
//#define SysClock 250 // System clock x 2 for 0.977 MHz DAC output
#define SysClock 280 // Overclock for 1.000 MHz DAC output
// 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)
// Data for the clock face is 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)
// 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 ;
int Hours=0, Mins=0, Secs=0, LEDCtr=0, Angle, StartX, StartY, Radius ;
float Radians ;
int tmp ;
@ -129,32 +140,14 @@ public:
MarginCount = 0 ;
}
// Setter functions...
void ReInit () {
// Re-initialises DMA channels to their initial state.
// Note: 1) DMA channels are not restarted, allowing for atomic (simultaneous) restart of both DAC channels later.
// 2) Cannot use dma_hw->abort on chained DMA channels, so using disable and re-enable instead.
// 3) This needs to be performed across both DAC channels to ensure phase sync is maintained.
// Disable both DMA channels associated with this DAC...
hw_clear_bits(&dma_hw->ch[data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
hw_clear_bits(&dma_hw->ch[ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
// Reset the data transfer DMA's to the start of the data Bitmap...
dma_channel_set_read_addr(data_chan, &DAC_data[0], false);
// Re-enable both DMA channels associated with this DAC...
hw_set_bits(&dma_hw->ch[data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
hw_set_bits(&dma_hw->ch[ctrl_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
}
int Set(int _type, int _val) {
switch (_type) {
case _Freq_:
Freq = _val ; // Frequency (numeric)
ReInit() ; // Stop and reset the DAC channel (no restart)
DACspeed(Freq * Range) ; // Update State machine run speed
break ;
case _Phase_:
Phase = _val ; // Phase shift (0->355 degrees)
ReInit() ; // Stop and reset the DAC channel (no restart)
DataCalc() ; // Recalc Bitmap and apply new phase value
break ;
case _Level_:
@ -194,7 +187,7 @@ public:
strcpy(ResultStr,MarginVW) ;
strcat(ResultStr,"Error - Minimum Frequency\n") ;
}
// TBD - remove hardcoded Max frequency
// TBD - remove hardcoded Max frequency
else if ((Freq*Range==1000000) && (_dirn==_Up)) { // Attempt to bump above upper limit
// else if ((Freq*Range>=MaxDACfreq) && (_dirn==_Up)) { // Attempt to bump above upper limit
MarginVW[MWidth - MarginCount] = '\0' ; // Calculate padding required for command characters and cursor
@ -260,9 +253,9 @@ public:
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...
// 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 )
@ -270,8 +263,8 @@ public:
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.
// 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
}
StatusString () ; // Update the terminal session
@ -282,7 +275,7 @@ public:
int _phase;
float a,b,x1,x2,g1,g2;
// Scale the phase shift to match data size...
// Scale the phase shift to match data size...
_phase = Phase * BitMapSize / 360 ; // Input range: 0 -> 360 (degrees)
// Output range: 0 -> 255 (bytes)
switch (Funct) {
@ -398,69 +391,58 @@ public:
}
};
class blink_forever { // Class to initialise a state machine to blink a GPIO pin
PIO pio ; // Class wide variables to share value with setter function
public:
uint pioNum, StateMachine, Freq, _offset ;
blink_forever(PIO _pio) {
pio = _pio; // transfer parameter to class wide var
pioNum = pio_get_index(_pio);
StateMachine = pio_claim_unused_sm(_pio, true); // Find a free state machine on the specified PIO - error if there are none.
_offset = pio_add_program(_pio, &pio_blink_program);
blink_program_init(_pio, StateMachine, _offset, PICO_DEFAULT_LED_PIN );
pio_sm_set_enabled(_pio, StateMachine, true);
}
// Setter function...
void Set_Frequency(int _frequency){
Freq = _frequency; // Copy parm to class var
// Frequency scaled by 2000 as blink.pio requires this number of cycles to complete...
float DAC_div = (float)clock_get_hz(clk_sys) /((float)_frequency*2000);
pio_sm_set_clkdiv(pio, StateMachine, DAC_div); // Set the State Machine clock speed
}
};
bool Repeating_Timer_Callback(struct repeating_timer *t) {
// Routine called 5 times per second...
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)>24) Hours=0 ; } // Bump hours when minutes and seconds = 0
// printf("%d\n",LEDCtr) ; // Debug
LEDCtr -- ;
if (LEDCtr>0) {
// LED off, and no change to the time for 4 out of 5 cycles...
gpio_put(PICO_DEFAULT_LED_PIN, 0); // LED is connected to PICO_DEFAULT_LED_PIN
} else {
// Falls through here once per second.
LEDCtr = 5 ;
gpio_put(PICO_DEFAULT_LED_PIN, 1); // LED is connected to PICO_DEFAULT_LED_PIN
// Calculate seconds hand...
i=0, Radius=127 ; // Radius=Length of seconds hand
Angle=270-(Secs*6) ; // Angle in degrees, shifted 90 degree anti-clockwise
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...
i=0, Radius=95 ; // Radius=Length of minutes hand
Angle=270-(Mins*6) ; // Angle in degrees, shifted 90 degree anti-clockwise
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...
i=0, Radius=64 ; // Radius=Length of 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.
Angle=5*(270-(((Hours%12)*6)+(Mins/12)%5)) ; // Angle in degrees, shifted 90 degree anti-clockwise,
// and scaled by 5 to provide range 0=>12
Radians=Angle*3.14159/180 ; // Angle in radians
StartX=Radius*cos(Radians)+MidX ;
StartY=Radius*sin(Radians)+MidY ;
while(i<steps) { HandsX[i+2*steps]=StartX+i*(MidX-StartX)/steps ;
HandsY[i+2*steps]=StartY+i*(MidY-StartY)/steps ;
i++ ; }
// Bump the clock...
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)>24) Hours=0 ; } // Bump hours when minutes and seconds = 0
// printf("%s%d:%d:%d - %d\n",MarginFW,Hours,Mins,Secs,tmp) ; // Debug
// Calculate seconds hand...
i=0, Radius=127 ; // Radius=Length of seconds hand
Angle=270-(Secs*6) ; // Angle in degrees, shifted 90 degree anti-clockwise
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...
i=0, Radius=95 ; // Radius=Length of minutes hand
Angle=270-(Mins*6) ; // Angle in degrees, shifted 90 degree anti-clockwise
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...
i=0, Radius=64 ; // Radius=Length of hours hand
// Note: Hours hand progresses between hours in 5 partial increments, each increment measuring 12 minutes.
// Each 12 minute increment adds an additional 6 degrees of rotation to the hours hand.
Angle=5*(270-(((Hours%12)*6)+(Mins/12)%5)) ; // Angle in degrees, shifted 90 degree anti-clockwise,
// and scaled by 5 to provide range 0=>12
Radians=Angle*3.14159/180 ; // Angle in radians
StartX=Radius*cos(Radians)+MidX ;
StartY=Radius*sin(Radians)+MidY ;
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;
}
@ -469,11 +451,11 @@ void VerText () {
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| Function Generator |\n"
"%s| Version 1.0.0 |\n"
"%s| 11th August 2023 |\n"
"%s|--------------------|\n",
sprintf(ResultStr, "%s|---------------------|\n"
"%s| Function Generator |\n"
"%s| Version 1.0.0 |\n"
"%s| 19th September 2023 |\n"
"%s|---------------------|\n",
MarginVW, MarginFW, MarginFW, MarginFW, MarginFW ) ;
}
@ -512,16 +494,18 @@ void HlpText () {
"%s<A/B/C>lennn - Level = nnn ( 0->100%%%% )\n"
"%s<A/B/C>le+ - Level + 1\n"
"%s<A/B/C>le- - Level - 1\n"
"%s<A/B/C>ti - Time mode (display analog clock)\n"
"%swhere...\n"
"%s<A/B/C> = DAC channel A,B or Both\n"
"%s<A/B/C> = DAC channel A,B or C=both\n"
"%snnn = Three digit numeric value\n",
MarginVW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW,
MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW,
MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW,
MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW ) ;
MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW, MarginFW,
MarginFW ) ;
}
void SysInfo (DAC DACobj[], blink_forever LED_blinky) {
void SysInfo (DAC DACobj[] ) {
// Print System Info and resource allocation detils, aligned to current margin settings...
// Note: 1) The following string requires '%%%%' to print '%' because...
// a) ResultStr is copied to outStr using sprintf - this reduces '%%%%' to '%%'
@ -534,15 +518,9 @@ void SysInfo (DAC DACobj[], blink_forever LED_blinky) {
sprintf(ResultStr,"%s|----------------------------------------------------------|\n"
"%s| System Info... |\n"
"%s|----------------------------------------------------------|\n"
"%s| Target board: Pico |\n"
"%s| RP2040 clock frequency: %7.3fMHz |\n"
"%s| Max DAC frequency: %7.3fMHz |\n"
"%s|----------------------------|-----------------------------|\n"
"%s| LED blinker | |\n"
"%s|----------------------------| |\n"
"%s| PIO: %2d | |\n"
"%s| State machine: %2d | |\n"
"%s| GPIO: %2d | |\n"
"%s| Frequency: %2dHz | |\n"
"%s| Max DAC frequency: %7.3fMHz |\n"
"%s|----------------------------|-----------------------------|\n"
"%s| DAC Channel A | DAC Channel B |\n"
"%s|----------------------------|-----------------------------|\n"
@ -553,14 +531,9 @@ void SysInfo (DAC DACobj[], blink_forever LED_blinky) {
"%s| Duty cycle: %3d%%%% | Duty cycle: %3d%%%% |\n"
"%s| Sine harmonic: %1d | Sine harmonic: %1d |\n"
"%s| Triangle Rise: %3d%%%% | Triangle Rise: %3d%%%% |\n",
MarginVW, MarginFW, MarginFW,
MarginVW, MarginFW, MarginFW, MarginFW,
MarginFW, (float)clock_get_hz(clk_sys)/1000000,
MarginFW, MaxDACfreq/1000000,
MarginFW, MarginFW, MarginFW,
MarginFW, LED_blinky.pioNum,
MarginFW, LED_blinky.StateMachine,
MarginFW, PICO_DEFAULT_LED_PIN,
MarginFW, LED_blinky.Freq,
MarginFW, MarginFW, MarginFW,
MarginFW, DACobj[_DAC_A].Level, DACobj[_DAC_B].Level,
MarginFW, DACobj[_DAC_A].Freq, DACobj[_DAC_B].Freq,
@ -631,11 +604,6 @@ static void MCP41020_Write (uint8_t _ctrl, uint8_t _data) {
// Scale the data byte to be in the range 0->255.
// Transmit data over the SPI bus to the Digi-Pot.
uint8_t buff[2];
// Depending on wiring, the MCP41020 Digi-Pot may have the channel selection bits reversed. If so, we will need to...
// if (_ctrl == 0x01) _ctrl = 0x02 ; // Swap channel A/B bits
// else if (_ctrl == 0x02) _ctrl = 0x01 ; // Note: Do not change if both channels are selected (code = 0x03)
buff[0] = _ctrl | 0x10 ; // Set command bit to Write data
buff[1] = _data * 2.55 ; // Scale data byte (100%->255)
cs_select(Level_CS) ; // Transmit data to Digi-Pot
@ -659,8 +627,8 @@ static void getLine() {
}
int SetVal(DAC DACobj[], int _Parm) {
// Common code for setting frequency, duty cycle, phase, waaveform and level.
// Handles options to set a specific value or bump up/down...
// Common code for setting frequency, duty cycle, phase, waveform and level.
// Handles options to set a specific value or bump up/down...
if (inStr[3] == '+') { // Bump up and grab result for SPI display...
if (SelectedChan & 0b01) result = DACobj[_DAC_A].Bump(_Parm,_Up);
if (SelectedChan & 0b10) result = DACobj[_DAC_B].Bump(_Parm,_Up) ;
@ -670,73 +638,85 @@ int SetVal(DAC DACobj[], int _Parm) {
} else { // Not a bump, so set the absolute value from Parm[0]...
if (SelectedChan & 0b01) result = DACobj[_DAC_A].Set(_Parm,Parm[0]) ;
if (SelectedChan & 0b10) result = DACobj[_DAC_B].Set(_Parm,Parm[0]) ;
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
}
// 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);
// 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
return result ;
}
int main() {
bool InvX=false, InvY=false ; // Clock mode flags to allow inverted output
set_sys_clock_khz(SysClock*1000, true) ; // Set Pico clock speed
MaxDACfreq = clock_get_hz(clk_sys) / BitMapSize ; // Calculate Maximum DAC output frequency for given CPU clock speed
int main() {
bool InvX=false, InvY=false ; // Clock display mode flags to allow inverted output
set_sys_clock_khz(SysClock*1000, true) ; // Set Pico clock speed
MaxDACfreq = clock_get_hz(clk_sys) / BitMapSize ; // Calculate Maximum DAC output frequency for given CPU clock speed
stdio_init_all() ;
spi_init(SPI_PORT, 500000); // Set SPI0 at 0.5MHz.
spi_init(SPI_PORT, 500000); // Set SPI0 at 0.5MHz...
gpio_set_function(PIN_CLK, GPIO_FUNC_SPI);
gpio_set_function(PIN_TX, GPIO_FUNC_SPI);
// Chip select is active-low, so initialise to a driven-high state...
gpio_init(Display_CS);
gpio_set_dir(Display_CS, GPIO_OUT);
gpio_put(Display_CS, 1);
gpio_init(Level_CS);
gpio_set_dir(Level_CS, GPIO_OUT);
gpio_put(Level_CS, 1);
gpio_init(Display_CS) ; // Initailse the required GPIO ports...
gpio_set_dir(Display_CS, GPIO_OUT) ;
gpio_put(Display_CS, 1) ; // Chip select is active-low, so initialise to high state
gpio_init(Level_CS) ;
gpio_set_dir(Level_CS, GPIO_OUT) ;
gpio_put(Level_CS, 1) ; // Chip select is active-low, so initialise to high state
gpio_init(PICO_DEFAULT_LED_PIN) ;
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT) ;
gpio_set_dir(PIN_CLK, GPIO_OUT) ; // Initialise remaining SPI connections...
gpio_set_dir(PIN_TX, GPIO_OUT) ;
// Setting Max slew rate and gpio drive strength keeps output linear at high frequencies...
for (int i=0; i<16; i++) {
gpio_set_slew_rate(i, GPIO_SLEW_RATE_FAST);
gpio_set_drive_strength(i, GPIO_DRIVE_STRENGTH_12MA);
gpio_set_slew_rate(i, GPIO_SLEW_RATE_FAST); // Setting Max slew rate and gpio drive strength keeps output
gpio_set_drive_strength(i, GPIO_DRIVE_STRENGTH_12MA); // linear at high frequencies...
}
// Initialise remaining SPI connections...
gpio_set_dir(PIN_CLK, GPIO_OUT);
gpio_set_dir(PIN_TX, GPIO_OUT);
struct repeating_timer timer;
add_repeating_timer_ms(-1000, Repeating_Timer_Callback, NULL, &timer); // 7ms - Short enough to prevent Nixie tube flicker
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
// Instantiate objects to control the various State Machines...
// Note: Both DAC channels need to be on the same PIO to achieve
// Atomic restarts for accurate phase sync.
// Instantiate objects to control the various State Machines...
// Note: Both DAC channels need to be on the same PIO to achieve
// Atomic restarts for accurate phase sync.
DAC DACobj[2]; // Array to hold the two DAC channel objects
DACobj[_DAC_A].DAC_chan('A',pio1,0); // First DAC channel object in array - resistor network connected to GPIO0->8
DACobj[_DAC_B].DAC_chan('B',pio1,8); // Second DAC channel object in array - resistor network connected to GPIO8->16
blink_forever LED_blinky(pio0); // Onboard LED blinky object
strcpy(LastCmd,"?") ; // Hitting return will give 'Help'
SPI_Display_Write(SysClock) ; // Pico system clock speed (in MHz)
MCP41020_Write(0x3, 50) ; // Both channels -> 50% output level
LED_blinky.Set_Frequency(1); // Flash LED at 1Hz- waiting for USB connection
while (!stdio_usb_connected()) { sleep_ms(100); } // Wait for USB connection...
LED_blinky.Set_Frequency(10); // Flash LED at 10Hz - USB connected.
SPI_Display_Write(DACobj[_DAC_A].Freq) ; // Frequency => SPI display
// Send (optional) start-up messages to terminal...
// Send (optional) start-up messages to terminal...
VerText() ; // Version text
printf(ResultStr) ; // Update terminal
// Atomic Restart - starting all 4 DMA channels simultaneously ensures phase sync between both DAC channels
dma_start_channel_mask(DAC_channel_mask);
// Atomic Restart - starting all 4 DMA channels simultaneously ensures phase sync between both DAC channels
dma_start_channel_mask(DAC_channel_mask); // Sets the 'Busy' flag in Ctrl reg
struct repeating_timer timer;
add_repeating_timer_ms(-200, Repeating_Timer_Callback, NULL, &timer) ; // 5 x per second to blink LED
while(1) {
ParmCnt=0, Parm[0]=0, Parm[1]=0, Parm[2]=0, Parm[3]=0 ; // Reset all command line parameters
@ -760,7 +740,7 @@ int main() {
DACobj[_DAC_A].StatusString() ;
DACobj[_DAC_B].StatusString() ;
}
if (inStr[0] == 'I') SysInfo(DACobj, LED_blinky); // TBD - inconsitant - make these global ??
if (inStr[0] == 'I') SysInfo(DACobj); // TBD - inconsitant - make these global ??
}
// For all remaining commands, the first character selects DAC channel A or B...
@ -797,57 +777,61 @@ int main() {
}
// Next two chars select the command...
if ((inStr[1]=='p')&(inStr[2]=='h')) SetVal(DACobj,_Phase_) ; // Phase
if ((inStr[1]=='l')&(inStr[2]=='e')) SetVal(DACobj,_Level_) ; // Level
if ((inStr[1]=='s')&(inStr[2]=='i')) SetVal(DACobj,_Sine_) ; // Sine wave (optional harmonic parameter)
if ((inStr[1]=='f')&(inStr[2]=='r')) { // Frequency
SetVal(DACobj,_Freq_) ; // Set value
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
}
if ((inStr[1]=='p')&(inStr[2]=='h')) SetVal(DACobj,_Phase_) ; // Phase
if ((inStr[1]=='l')&(inStr[2]=='e')) SetVal(DACobj,_Level_) ; // Level
if ((inStr[1]=='s')&(inStr[2]=='i')) SetVal(DACobj,_Sine_) ; // Sine wave (optional harmonic parameter)
if ((inStr[1]=='f')&(inStr[2]=='r')) SetVal(DACobj,_Freq_) ; // Frequency
// The next two commands need different default values...
if (strlen(inStr)==3) Parm[0] = 50 ; // If no value provided, set default to 50
if ((inStr[1]=='s')&(inStr[2]=='q')) SetVal(DACobj,_Square_) ; // Set Square wave (optional duty cycle parameter)
if ((inStr[1]=='t')&(inStr[2]=='r')) SetVal(DACobj,_Triangle_) ; // Set Triangle wave (optional duty cycle parameter)
if (strlen(inStr)==3) Parm[0] = 50 ; // If no value provided, set default to 50
if ((inStr[1]=='s')&(inStr[2]=='q')) SetVal(DACobj,_Square_) ; // Set Square wave (optional duty cycle parameter)
if ((inStr[1]=='t')&(inStr[2]=='r')) SetVal(DACobj,_Triangle_) ; // Set Triangle wave (optional duty cycle parameter)
if ((inStr[1]=='t')&(inStr[2]=='i')) { // Time display...
DACobj[_DAC_A].Set(_Phase_, 0) ; // Phase lock
DACobj[_DAC_B].Set(_Phase_, 0) ;
if ((inStr[1]=='t')&(inStr[2]=='i')) { // Time display...
// 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...
for (int gpio = 0; gpio < 16; gpio++) { // Grabs the GPIO back from the State machines
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
}
// Abort the data channels...
dma_channel_abort(DACobj[_DAC_A].data_chan);
dma_channel_abort(DACobj[_DAC_B].data_chan);
// Disable both DMA channels associated with this DAC...
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_A].data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
hw_clear_bits(&dma_hw->ch[DACobj[_DAC_B].data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
// 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);
pio_sm_set_enabled(pio1,0,false) ; // disable State machine 0 !! HARD CODED !!
pio_sm_set_enabled(pio1,1,false) ; // disable State machine 1
for (uint i=0; i<16; i++) { // Grab the GPIO back from the State machines
gpio_init(i);
gpio_set_dir(i, GPIO_OUT);
}
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
float Radians ;
int outX, outY ;
// Draw the clock face...
for (int i=0; i<sizeof(FaceX); i++) {
if (InvX) { gpio_put_masked(0x00ff,FaceX[i]) ; } // Write inverted data byte to DAC A
else { gpio_put_masked(0x00ff,255-FaceX[i]) ; } // Write non-inverted data byte to DAC A
if (InvY) { gpio_put_masked(0xff00,FaceY[i]<<8) ; } // Write inverted data byte to DAC B
else { gpio_put_masked(0xff00,255-FaceY[i]<<8) ; } // Write non-inverted data byte to DAC B
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) { gpio_put_masked(0x00ff,outX) ; } // Write inverted data byte to DAC A
else { gpio_put_masked(0x00ff,255-outX) ; } // Write non-inverted data byte to DAC A
if (InvY) { gpio_put_masked(0xff00,outY<<8) ; } // Write inverted data byte to DAC B
else { gpio_put_masked(0xff00,255-outY<<8) ; } // Write non-inverted 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
if (InvX) { gpio_put_masked(0x00ff,HandsX[i]) ; } // Write inverted data byte to DAC A
else { gpio_put_masked(0x00ff,255-HandsX[i]) ; } // Write non-inverted data byte to DAC A
if (InvY) { gpio_put_masked(0xff00,HandsY[i]<<8) ; } // Write inverted data byte to DAC B
else { gpio_put_masked(0xff00,255-HandsY[i]<<8) ; } // Write non-inverted data byte to DAC B
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) { gpio_put_masked(0x00ff,outX) ; } // Write inverted data byte to DAC A
else { gpio_put_masked(0x00ff,255-outX) ; } // Write non-inverted data byte to DAC A
if (InvY) { gpio_put_masked(0xff00,outY<<8) ; } // Write inverted data byte to DAC B
else { gpio_put_masked(0xff00,255-outY<<8) ; } // Write non-inverted data byte to DAC B
sleep_us(2) ; // Pause for on-screen persistance
}
@ -878,17 +862,21 @@ int main() {
}
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 now
Repeating_Timer_Callback(&timer) ;
printf("\n%sClock set to %02d:%02d:%02d\n>",MarginFW,Hours,Mins,Secs) ;
}
else if ((c=='q') or (c=='Q')) {
strcpy(ResultStr," Quit clock mode\n") ; // Prevents error message
// Re-enable both DMA channels associated with this DAC...
hw_set_bits(&dma_hw->ch[DACobj[_DAC_A].data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
hw_set_bits(&dma_hw->ch[DACobj[_DAC_B].data_chan].al1_ctrl, DMA_CH0_CTRL_TRIG_EN_BITS);
for (uint i=0; i<16; i++) { pio_gpio_init(pio1, i); } // Hand the GPIO's back to the state machines
// 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(pio1,0,true) ; // Re-enable State machine 0 !! HARD CODED !!
pio_sm_set_enabled(pio1,1,true) ; // Re-enable State machine 1
// Re-init the state machines ????
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
strcpy(ResultStr," Quit clock mode\n") ; // Prevents error message
}
}
}
@ -896,31 +884,44 @@ int main() {
// The final command is a continual loop creating the sweep function...
if ((inStr[1] == 's') & (inStr[2] == 'w')) { // Sweep
// Parm[0]=Low frequency, Parm[1]=High frequency, Parm[2]=Scan speed, Parm[3]=Low/High pause
// Parm[0]=Low frequency, Parm[1]=High frequency, Parm[2]=Scan speed, Parm[3]=Low/High pause
i = Parm[0];
for (;;) {
if (SelectedChan & 0b01) result = DACobj[_DAC_A].Set(_Freq_,i) ; // Set frequency, display status
if (SelectedChan & 0b10) result = DACobj[_DAC_B].Set(_Freq_,i) ; // Set frequency, display status
dma_start_channel_mask(DAC_channel_mask); // Atomic restart all 4 DMA channels...
printf(ResultStr) ; // Update terminal
ResultStr[0] = '\0' ; // Reset the string variable
SPI_Display_Write(i); // Update SPI display
if (SelectedChan & 0b01) result = DACobj[_DAC_A].Set(_Freq_,i) ; // Set frequency, display status
if (SelectedChan & 0b10) result = DACobj[_DAC_B].Set(_Freq_,i) ; // Set frequency, display status
dma_start_channel_mask(DAC_channel_mask); // Atomic restart all 4 DMA channels...
printf(ResultStr) ; // Update terminal
ResultStr[0] = '\0' ; // Reset the string variable
SPI_Display_Write(i); // Update SPI display
if (i==Parm[0]) { dirn = 1;
sleep_ms(Parm[3]); }
if (i>=Parm[1]) { dirn =-1;
sleep_ms(Parm[3]); }
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
// 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);
dma_start_channel_mask(DAC_channel_mask); // Atomic restart both DAC channels
i = i + dirn;
c = getchar_timeout_us (0); // Non-blocking char input
c = getchar_timeout_us (0); // Non-blocking char input
if ((c>=32) & (c<=126)) {
strcpy(ResultStr," Exit sweep mode\n") ; // Prevents error message
break; } // exit on keypress
sleep_ms(Parm[2]); // Speed of scan
strcpy(ResultStr," Exit sweep mode\n") ; // Prevents error message
break; } // exit on keypress
sleep_ms(Parm[2]); // Speed of scan
}
}
if (strlen(ResultStr) == 0) { // No result can only mean unrecognised command
strcpy(MarginVW,MarginFW) ; // Reset Variable Width margin
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

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,35 +0,0 @@
.program pio_blink
; Turn on LED for 1002 cycles and off for 1002 cycles.
; Large delays are required to allow the State Machine to toggle at frequencies as low as 1Hz.
; Note: Oscilloscope shows this runs about 2% fast indicating an issue with the cycle count.
.wrap_target
set pins, 1 ; Turn LED on
set x,25
; 2 cycles to this point
label01:
nop [19] ; 20 cycles
nop [18] ; 19 cycles
jmp x--, label01 ; 1 cycles
; ; 2 + 25*(20+19+1) = 1002 cycles to this point
; (restart cycle count)
set pins, 0 ; Turn LED off
set x,25
; 2 cycles to this point
label02:
nop [19] ; 20 cycles
nop [18] ; 19 cycles
jmp x--, label02 ; 1 cycles
; ; 2 + 25*(20+19+1) = 1002 cycles to this point
.wrap ; Blink forever!
% c-sdk {
// this is a raw helper function for use by the user which sets up the GPIO output, and configures the SM to output on a particular pin
void blink_program_init(PIO pio, uint sm, uint offset, uint pin) {
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_config c = pio_blink_program_get_default_config(offset);
sm_config_set_set_pins(&c, pin, 1);
pio_sm_init(pio, sm, offset, &c);
}
%}