diff --git a/Function Generator/DAC.pio b/Function Generator/DAC.pio index efd05b7..af3b658 100644 --- a/Function Generator/DAC.pio +++ b/Function Generator/DAC.pio @@ -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); } diff --git a/Function Generator/FunctionGenerator.cpp b/Function Generator/FunctionGenerator.cpp index 6c9475c..09c063a 100644 --- a/Function Generator/FunctionGenerator.cpp +++ b/Function Generator/FunctionGenerator.cpp @@ -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 #include #include @@ -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(i12 - Radians=Angle*3.14159/180 ; // Angle in radians - StartX=Radius*cos(Radians)+MidX ; - StartY=Radius*sin(Radians)+MidY ; - while(i59) 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(i12 + Radians=Angle*3.14159/180 ; // Angle in radians + StartX=Radius*cos(Radians)+MidX ; + StartY=Radius*sin(Radians)+MidY ; + while(ilennn - Level = nnn ( 0->100%%%% )\n" "%sle+ - Level + 1\n" "%sle- - Level - 1\n" + "%sti - Time mode (display analog clock)\n" "%swhere...\n" - "%s = DAC channel A,B or Both\n" + "%s = 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",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 diff --git a/Function Generator/FunctionGenerator.uf2 b/Function Generator/FunctionGenerator.uf2 new file mode 100644 index 0000000..a48d677 Binary files /dev/null and b/Function Generator/FunctionGenerator.uf2 differ diff --git a/Function Generator/blink.pio b/Function Generator/blink.pio deleted file mode 100644 index 584140e..0000000 --- a/Function Generator/blink.pio +++ /dev/null @@ -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); -} -%}