// file: pico.c // author: KLL /* * v01 PoorManScope with 3 channel * sample A0 A1 A2 as 320 array / lines in batch modus * and send to RPI4 as CSV lines (for compatibility only 10bit resolution needed also graph only has 250 px hight ) * 1023,1023,1023, * for show in ( Flask Werkzeug Jinja2 Python ) web server * myblog PMS3 * */ /* * CMakeLists.txt // _____________________________ please make this file in your 'project' directory with following content: cmake_minimum_required(VERSION 3.12) #include(pico_sdk_import.cmake) include(~/pico/pico-sdk/external/pico_sdk_import.cmake) project(project) pico_sdk_init() # cross compile a c++ code for the PICO add_executable(pico pico.c) # Pull in our pico_stdlib which pulls in commonly used features target_link_libraries(pico pico_stdlib hardware_adc hardware_rtc hardware_pwm pico_multicore ) # enable usb output, disable uart output pico_enable_stdio_usb(pico 1) pico_enable_stdio_uart(pico 0) # create map/bin/hex/uf2 file etc. pico_add_extra_outputs(pico) */ #include #include #include "pico/stdlib.h" #include "pico/time.h" #include "pico/util/datetime.h" #include "hardware/gpio.h" #include "hardware/adc.h" #include "hardware/rtc.h" #include "hardware/timer.h" // testsignal: PWM in THREAD #include "hardware/pwm.h" #include "hardware/clocks.h" #include "pico/multicore.h" // DIAG print diagnostic info bool DIAG = false; //true; //false; //true; //___ code testing bool DIAGM = false; //true; //___________________ Mega Loops print bool batch = true; //____________________________ not print, fill array // LED const uint LED_PIN = 25; bool LED_stat = false; // ADC const float conversion_factor = 3.3f / (1 << 12); // 12-bit conversion, assume max value == ADC_VREF == 3.3 V const float conversion_line = 101.0f / (1 << 12); // 12-bit conversion, assume max value == ADC_VREF == 3.3 V make it 101 character for Chart Line // RTC char datetime_buf[256]; char *datetime_str = &datetime_buf[0]; datetime_t t = { // Start .year = 2021, .month = 03, .day = 03, .dotw = 3, // 0 is Sunday, so 6 is Saturday .hour = 00, .min = 00, .sec = 00 }; // START in THREAD // PWM uint16_t fade = 66; //__________________________ LED start 10% PWM # define Aout0 22 // 25 is on board LED, now use 22 // GP22 pin 29 for jumper cable to ADC0 GP26 pin 31 for scope test int setup_pwm() { //_____________________________ PWM INIT gpio_set_function(Aout0, GPIO_FUNC_PWM); uint slice_num = pwm_gpio_to_slice_num(Aout0); // pwm_config config = pwm_get_default_config(); // pwm_config_set_clkdiv(&config, 4.f); // pwm_init(slice_num, &config, true); //_ try a 1000 Hz code from https://www.raspberrypi.org/forums/viewtopic.php?t=303116#p1815288 uint32_t f_pwm = 1000; // frequency we want to generate uint32_t f_sys = clock_get_hz(clk_sys); //___ typically 125'000'000 Hz float divider = f_sys / 1000000UL; //_______ let's arbitrarily choose to run pwm clock at 1MHz pwm_set_clkdiv(slice_num, divider); //_______ pwm clock should now be running at 1MHz uint32_t top = 1000000UL/f_pwm -1; //_______ TOP is u16 has a max of 65535, being 65536 cycles pwm_set_wrap(slice_num, top); pwm_set_enabled(slice_num, true); //_________ let's go! pwm_set_gpio_level(Aout0, fade ); //_________ duty cycle } int setup() { stdio_init_all(); //___________________________________________ LED related // gpio_init(LED_PIN); // gpio_set_dir(LED_PIN, GPIO_OUT); //___________________________________________ ADC related adc_init(); adc_gpio_init(26); //________________________ Make sure GPIO is high-impedance, no pullups etc adc_gpio_init(27); adc_gpio_init(28); adc_set_temp_sensor_enabled(true); //___________________________________________ RTC related rtc_init(); //_______________________________ Start the RTC rtc_set_datetime(&t); //___________________________________________ end setup printf("\ni am PICO\n"); //__________________ i never see that ? setup_pwm(); //_____________________________ test signal on pin29 GP22 } int LED_toggle(bool printit) { LED_stat = !LED_stat; //_____________________ toggle if ( LED_stat ) { gpio_put(LED_PIN, 1); if ( printit ) { printf(" LED ON \n"); } } else { gpio_put(LED_PIN, 0); if ( printit ) { printf(" LED OFF\n"); } } } int get_Ains() { //___ print as Volt adc_select_input(0); // Select ADC input 0 (GPIO26) pin 31 float A0 = adc_read() * conversion_factor; adc_select_input(1); // Select ADC input 1 (GPIO27) pin 32 float A1 = adc_read() * conversion_factor; adc_select_input(2); // Select ADC input 2 (GPIO28) pin 34 float A2 = adc_read() * conversion_factor; // A3 on GP29 is internal wired on the board and used by cpu ADC code? adc_select_input(4); // Select ADC input ? T = 27 - (ADC_Voltage - 0.706)/0.001721 float A4 = 27.0 - ( adc_read() * conversion_factor - 0.706)/0.001721; printf("A0, %.3f ,A1, %.3f ,A2, %.3f, V; A4, %.1f , degC cpu temp,\n", A0, A1, A2, A4); } //_______________________________________________ BATCH READ to Array for PMS3 int allA0 [360]; int allA1 [360]; int allA2 [360]; int dtp = 5; //__________________________________ start pointer setting ( 0 means only sample A0 no wait / 1 means sample A0&1&2 no wait ) const int dtpm = 13; //__________________________ max selectable number by browser operation ( already see com errors "too short line" ) int batch_tune [] = { 0, 0 , 10, 25, 50, 100, 500, 1000, 2500, 5000,10000,25000,50000,100000}; //_ sleep us after sample //__ dtp ____________ 0___1____2___3___4____5____6_____7_____8_____9____10____11____12_____13______ pointer by [-][+] ( 10 about 100Hz ) //__ ms_______________2___4___ 7__13__22___40__183___364___900__1805__3603__9000_18000__36000______ batch time //__ Hz____________200k_90k__50k_28k_16k___9k___2k___990___398___199___100____40____20_____10______ sample freq int get_Ains_array(bool printit,int tp) { rtc_get_datetime(&t); //_____________________ get the start time uint64_t batch_time = time_us_64(); for (int count=0;count<360;count++){ //______ batch read to arrays adc_select_input(0); // Select ADC input 0 (GPIO26) pin 31 allA0[count] = adc_read(); if ( tp > 0 ) { adc_select_input(1); // Select ADC input 1 (GPIO27) pin 32 allA1[count] = adc_read(); adc_select_input(2); // Select ADC input 2 (GPIO28) pin 34 allA2[count] = adc_read(); } else { // set array vals to 0 allA1[count] = 0; allA2[count] = 0; } sleep_us(batch_tune[tp]); } batch_time = time_us_64() - batch_time ; //_______ calc delta time datetime_to_str(datetime_str, sizeof(datetime_buf), &t); float samplefreq = 360000000.0 / batch_time ; if ( printit ) { printf("batch start %s ,delta_ms %0.1f , freq_Hz %0.1f\n", datetime_str,batch_time/1000.0,samplefreq); } //_ no lf if (tp > 0 ) { printf(",%d,channela,0,channelb,1,channelc,2,batchtime:msec,%0.1f,samples,360,samplefreq,%0.1f,Hz,\n",dtp,batch_time/1000.0,samplefreq); } else { printf(",%d,channela,0,channelb,_,channelc,_,batchtime:msec,%0.1f,samples,360,samplefreq,%0.1f,Hz,\n",dtp,batch_time/1000.0,samplefreq); } //_ report it to USB / PMS ( what has 5 DIV for 5 V SCOPE with 1023 , so must scale 4096 == 3v3 down ) for (int count=0;count<360;count++){ //______ OFFLINE print arrays // int thisA0 = allA0[count]>>2; //_________ 4096 to 1023 int thisA0 = (int)(allA0[count]*0.165); //__________ 5v down to 3v3 and /4 // int thisA1 = allA1[count]>>2; //_____________ 4096 to 1023 int thisA1 = (int)(allA1[count]*0.165); //__________ 5v down to 3v3 and /4 // int thisA2 = allA2[count]>>2; //_____________ 4096 to 1023 int thisA2 = (int)(allA2[count]*0.165); //__________ 5v down to 3v3 and /4 printf("%d,%d,%d,\n",thisA0,thisA1,thisA2); } LED_toggle(false); //________________________ show PICO is working } int get_RTC(bool printit) { //___________________ print date time no tailing lf rtc_get_datetime(&t); datetime_to_str(datetime_str, sizeof(datetime_buf), &t); if ( printit ) { printf("%s ", datetime_str); } //_ no lf } // Multi Tasking JOB counter structure uint32_t main_count = 0; uint32_t main_limit = 1000000; //________________ count to M // PICO about 3 times per sec ? 12 times faster as Arduino UNO ? uint32_t main_Mloops = 0; bool menu_init = true; //________________________ after first Mloop print menu once int c_usb; //____________________________________ operator menu input char int job0() { //__________________________________ JOB0 ( after 1.000.000 loops ) if ( DIAGM ) { get_RTC(DIAGM); //___________________________ show time LED_toggle(DIAGM); //________________________ LED toggle printf("Mloops %d \n",main_Mloops); // show Mloops counter } } int ser0() { //__________________________________ check for operator input after counter / do not check serial buffer every loop c_usb = getchar_timeout_us(0); //________ OPERATION switch(c_usb) { case '-': //_________________________ batcht time down dtp--; if ( dtp < 0 ) { dtp = 0; } break; case '+': //_________________________ batch time up dtp++; if ( dtp > dtpm ) { dtp = dtpm; } break; case 'd': //_________________________ print debug info DIAG = !DIAG; break; case 'l': //_________________________ print MEGA LOOP timing DIAGM = !DIAGM; break; default: ;//printf("what was that?"); } } int job_check() { //_____________________________ basic counter loop main_count += 1; //__________________________ cycles if ( main_count >= main_limit ) { main_count = 0; //_______________________ reset main_Mloops += 1; job0(); } ser0(); //___________________________________ check USB input with its own counter get_Ains_array(DIAG,dtp); //_________________ this is what we are here for } int main() { setup(); //__________________________________ SETUP while (1) { //_______________________________ LOOP job_check(); } } // ______________________________________________ END