├── FPGA ├── clock.sdc ├── pps.v ├── coarsecounter.v ├── bin2bcd.v ├── pins.pcf ├── counter_test.v ├── pdm_test.v ├── spi_m_test.v ├── pwm.v ├── rtc.v ├── README.md ├── delayPPS.v ├── fifo.v ├── spi_s_test.v ├── spi_master.v ├── ADS8681.v ├── tdc7200.v ├── nixie.v └── main.v ├── PCB ├── schematic.pdf ├── README.md └── NixieAtomicClock.kicad_pro ├── RPI_Code ├── dbSetting.py ├── requirements.txt ├── mountdrive.sh ├── autoBrightness │ ├── Adafruit-PWM-Servo-Driver-Library-master │ │ ├── .gitignore │ │ ├── library.properties │ │ ├── keywords.txt │ │ ├── .github │ │ │ ├── workflows │ │ │ │ └── githubci.yml │ │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ │ └── ISSUE_TEMPLATE.md │ │ ├── README.md │ │ ├── license.txt │ │ ├── examples │ │ │ ├── gpiotest │ │ │ │ └── gpiotest.ino │ │ │ ├── pwmtest │ │ │ │ └── pwmtest.ino │ │ │ ├── oscillator │ │ │ │ └── oscillator.ino │ │ │ └── servo │ │ │ │ └── servo.ino │ │ ├── Adafruit_PWMServoDriver.h │ │ └── Adafruit_PWMServoDriver.cpp │ ├── TSL2561 │ │ ├── library.properties │ │ ├── README.txt │ │ ├── .github │ │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ │ └── ISSUE_TEMPLATE.md │ │ ├── examples │ │ │ └── tsl2561 │ │ │ │ └── tsl2561.ino │ │ ├── TSL2561.h │ │ └── TSL2561.cpp │ ├── Adafruit_PWMServoDriver.h │ ├── main.cpp │ ├── TSL2561.h │ ├── TSL2561.cpp │ └── Adafruit_PWMServoDriver.cpp ├── startup.sh ├── uploadFPGA.py ├── moveFile.py ├── uploadFPGA.sh ├── readADC │ ├── parsebin.m │ └── readADC.c ├── fanControl.py ├── README.md ├── calibrateClock.py ├── uploadMAC.py └── uploadClock.py ├── README.md └── .gitignore /FPGA/clock.sdc: -------------------------------------------------------------------------------- 1 | create_clock -period 100 -name {p:vclk} [get_ports {p:vclk}] -------------------------------------------------------------------------------- /PCB/schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/will127534/RaspberryPiAtomicNixieClock/HEAD/PCB/schematic.pdf -------------------------------------------------------------------------------- /RPI_Code/dbSetting.py: -------------------------------------------------------------------------------- 1 | ifuser = "admin" 2 | ifpass = "" 3 | ifdb = "" 4 | ifhost = "127.0.0.1" 5 | ifport = 8086 -------------------------------------------------------------------------------- /RPI_Code/requirements.txt: -------------------------------------------------------------------------------- 1 | pyserial 2 | python-influxdb 3 | simple-pid 4 | adafruit-circuitpython-TMP117 5 | python-dateutil -------------------------------------------------------------------------------- /RPI_Code/mountdrive.sh: -------------------------------------------------------------------------------- 1 | sudo mount -t tmpfs -o size=500M tmpfs /home/pi/ramdisk/ 2 | sudo mount /dev/nvme0n1p1 /home/pi/external/ 3 | sudo sysctl fs.pipe-max-size=33554432 -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/.gitignore: -------------------------------------------------------------------------------- 1 | # osx 2 | .DS_Store 3 | 4 | # doxygen 5 | Doxyfile* 6 | doxygen_sqlite3.db 7 | html 8 | *.tmp 9 | -------------------------------------------------------------------------------- /RPI_Code/startup.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/python3 /home/pi/upload.py 2 | screen -dmS Sensor_Env python3 /home/pi/uploadEnv.py 3 | screen -dmS Sensor_AC python3 /home/pi/uploadAC.py 4 | screen -dmS Fan_control python3 /home/pi/fanControl.py 5 | sleep 90 6 | /usr/bin/python3 /home/pi/uploadClock.py 7 | -------------------------------------------------------------------------------- /PCB/README.md: -------------------------------------------------------------------------------- 1 | # PCB Files 2 | Designed with KiCad v5.99 nightly build 3 | 4 | ## PCB Errata 5 | 1. EMC2301 package is wrong 6 | 2. eFUSE (TPS259270) Enable pin should connect to VIN via a resistor 7 | 8 | ## Images 9 | ![](https://i.imgur.com/LAtZCIN.png) 10 | ![](https://i.imgur.com/RnxeZhN.png) 11 | 12 | 13 | 14 | 15 | good luck finding the stock for LDO and DC-DC converters :D -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/library.properties: -------------------------------------------------------------------------------- 1 | name=TSL2561 Arduino Library 2 | version=1.0.0 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Arduino library for using the TSL2561 Luminosity sensor 6 | paragraph=Arduino library for using the TSL2561 Luminosity sensor 7 | category=Sensors 8 | url=https://github.com/adafruit/TSL2561-Arduino-Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit PWM Servo Driver Library 2 | version=2.4.0 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Adafruit PWM Servo Driver Library 6 | paragraph=Adafruit PWM Servo Driver Library 7 | category=Device Control 8 | url=https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RaspberryPi Atomic Nixie Clock 2 | 3 | [Full description is in here](https://www.willwhang.dev/RaspberryPi-Atomic-Nixie-Clock/) 4 | 5 | ![](https://i.imgur.com/K8xKzDb.jpg) 6 | 7 | ## Sys Arch 8 | ![](https://i.imgur.com/zrFgwyR.jpg) 9 | 10 | ## Source File List 11 | * PCB - PCB related board designed with KiCad v5.99 nightly 12 | * FPGA Code - Verilog files 13 | * Raspberry Pi Code - Python + C code to interact with FPGA 14 | -------------------------------------------------------------------------------- /RPI_Code/uploadFPGA.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import time 3 | import os 4 | 5 | GPIO.setwarnings(False) 6 | GPIO.setmode(GPIO.BCM) 7 | 8 | FPGA_RST = 27 9 | FPGA_CE = 8 10 | 11 | GPIO.setup(FPGA_RST, GPIO.OUT) 12 | GPIO.setup(FPGA_CE, GPIO.OUT) 13 | 14 | GPIO.output(FPGA_CE, 0) 15 | 16 | GPIO.output(FPGA_RST, 0) 17 | time.sleep(1) 18 | GPIO.output(FPGA_RST, 1) 19 | 20 | os.system('sudo bash ./uploadfpga.sh main_bitmap.bin') 21 | 22 | GPIO.output(FPGA_CE, 1) 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # For PCBs designed using KiCad: http://www.kicad-pcb.org/ 2 | # Format documentation: http://kicad-pcb.org/help/file-formats/ 3 | 4 | # Temporary files 5 | *.000 6 | *.bak 7 | *.bck 8 | *.kicad_pcb-bak 9 | *.sch-bak 10 | *~ 11 | _autosave-* 12 | *.tmp 13 | *-save.pro 14 | *-save.kicad_pcb 15 | fp-info-cache 16 | *.kicad_prl 17 | 18 | NixieAtomicClock-backups/ 19 | 20 | # Netlist files (exported from Eeschema) 21 | *.net 22 | 23 | # Autorouter files (exported from Pcbnew) 24 | *.dsn 25 | *.ses 26 | 27 | # Exported BOM files 28 | *.xml 29 | *.csv 30 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/README.txt: -------------------------------------------------------------------------------- 1 | **DEPRECATED** 2 | Please use new version of library: 3 | https://github.com/adafruit/Adafruit_TSL2561 4 | 5 | --------------------------- 6 | This is an Arduino library for the TSL2561 digital luminosity (light) sensors. 7 | 8 | Pick one up at http://www.adafruit.com/products/439 9 | 10 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder TSL2561. Check that the TSL2561 folder contains TSL2561.cpp and TSL2561.h 11 | 12 | Place the TSL2561 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. 13 | -------------------------------------------------------------------------------- /FPGA/pps.v: -------------------------------------------------------------------------------- 1 | module pulsepersecond ( 2 | input clk_in, 3 | input [23:0] counter_value, 4 | output clk_out, 5 | output pps_out, 6 | input rst 7 | ); 8 | 9 | //-- divisor register 10 | reg [23:0] divcounter; 11 | reg pps_pwm; 12 | wire overflow; 13 | 14 | assign overflow = (divcounter == counter_value); 15 | 16 | always @(posedge clk_in) begin 17 | if (overflow | rst == 0) begin 18 | divcounter <= 0; 19 | end 20 | else if (clk_in) begin 21 | divcounter <= divcounter + 1; 22 | end 23 | end 24 | 25 | assign clk_out = (divcounter == 24'h000000); 26 | assign pps_out = (divcounter < 24'h4C4B40); 27 | endmodule -------------------------------------------------------------------------------- /RPI_Code/moveFile.py: -------------------------------------------------------------------------------- 1 | import glob, os 2 | 3 | os.chdir("/home/pi/ramdisk/") 4 | fileList = [] 5 | for file in glob.glob("Wave*"): 6 | print(file) 7 | fileList.append(file) 8 | 9 | fileList.sort() 10 | fileList.pop() 11 | 12 | for file in fileList: 13 | print(file) 14 | os.system('gzip -k ' + file) 15 | os.system('cp ' + file + '.gz ' + '/home/pi/external' ) 16 | os.system('rm ' + file + '.gz ') 17 | os.system('rm ' + file ) 18 | 19 | fileList = [] 20 | for file in glob.glob("ACFREQ*"): 21 | print(file) 22 | fileList.append(file) 23 | 24 | fileList.sort() 25 | fileList.pop() 26 | 27 | for file in fileList: 28 | print(file) 29 | os.system('cp ' + file + ' /home/pi/external' ) 30 | os.system('rm ' + file ) 31 | 32 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Classes, datatypes (KEYWORD1) 3 | ####################################### 4 | 5 | Adafruit_PWMServoDriver KEYWORD1 6 | 7 | ####################################### 8 | # Methods and Functions (KEYWORD2) 9 | ####################################### 10 | 11 | begin KEYWORD2 12 | reset KEYWORD2 13 | sleep KEYWORD2 14 | wakeup KEYWORD2 15 | setExtClk KEYWORD2 16 | setPWMFreq KEYWORD2 17 | setOutputMode KEYWORD2 18 | getPWM KEYWORD2 19 | setPWM KEYWORD2 20 | setPin KEYWORD2 21 | readPrescale KEYWORD2 22 | writeMicroseconds KEYWORD2 23 | setOscillatorFrequency KEYWORD2 24 | getOscillatorFrequency KEYWORD2 25 | 26 | ####################################### 27 | # Constants (LITERAL1) 28 | ####################################### 29 | FREQUENCY_OSCILLATOR LITERAL1 30 | -------------------------------------------------------------------------------- /FPGA/coarsecounter.v: -------------------------------------------------------------------------------- 1 | module CounterModule( 2 | input inputsig, 3 | input clk, 4 | input rst, 5 | input falling_rising, 6 | output reg [31:0] counter, 7 | output trigger 8 | ); 9 | 10 | reg [1:0] FallingPulse; 11 | reg inputSig_d; 12 | 13 | reg [31:0] internalCounter; 14 | 15 | assign trigger = falling_rising? (FallingPulse==2'b10) : (FallingPulse==2'b01); 16 | 17 | always @(posedge clk) begin 18 | inputSig_d <= inputsig; 19 | FallingPulse <= {FallingPulse[0],inputSig_d}; 20 | if (~rst) begin 21 | internalCounter <= 0; 22 | counter <= 0; 23 | end 24 | else begin 25 | if (trigger) begin 26 | internalCounter <= 1; 27 | counter <= internalCounter; 28 | end 29 | else begin 30 | internalCounter <= internalCounter + 1; 31 | end 32 | end 33 | end 34 | endmodule 35 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/setup-python@v1 11 | with: 12 | python-version: '3.x' 13 | - uses: actions/checkout@v2 14 | - uses: actions/checkout@v2 15 | with: 16 | repository: adafruit/ci-arduino 17 | path: ci 18 | 19 | - name: pre-install 20 | run: bash ci/actions_install.sh 21 | 22 | - name: test platforms 23 | run: python3 ci/build_platform.py main_platforms 24 | 25 | - name: clang 26 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 27 | 28 | - name: doxygen 29 | env: 30 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 31 | PRETTYNAME : "Adafruit PCA9685 PWM Library" 32 | run: bash ci/doxy_gen_and_deploy.sh 33 | -------------------------------------------------------------------------------- /FPGA/bin2bcd.v: -------------------------------------------------------------------------------- 1 | module bin2bcd( 2 | input [7:0] bin, 3 | output [11:0] bcd 4 | ); 5 | 6 | //Internal variables 7 | reg [11:0] bcd; 8 | reg [3:0] i; 9 | 10 | //Always block - implement the Double Dabble algorithm 11 | always @(bin) 12 | begin 13 | bcd = 0; //initialize bcd to zero. 14 | for (i = 0; i < 8; i = i+1) //run for 8 iterations 15 | begin 16 | bcd = {bcd[10:0],bin[7-i]}; //concatenation 17 | 18 | //if a hex digit of 'bcd' is more than 4, add 3 to it. 19 | if(i < 7 && bcd[3:0] > 4) 20 | bcd[3:0] = bcd[3:0] + 3; 21 | if(i < 7 && bcd[7:4] > 4) 22 | bcd[7:4] = bcd[7:4] + 3; 23 | if(i < 7 && bcd[11:8] > 4) 24 | bcd[11:8] = bcd[11:8] + 3; 25 | end 26 | end 27 | 28 | endmodule 29 | 30 | //https://verilogcodes.blogspot.com/2015/10/verilog-code-for-8-bit-binary-to-bcd.html -------------------------------------------------------------------------------- /RPI_Code/uploadFPGA.sh: -------------------------------------------------------------------------------- 1 | echo "" 2 | if [ $# -ne 1 ]; then 3 | echo "Usage: $0 FPGA-bin-file " 4 | exit 1 5 | fi 6 | 7 | 8 | #echo "" 9 | #echo "Changing 8 direction to out" 10 | #echo out > /sys/class/gpio/gpio8/direction 11 | #cat /sys/class/gpio/gpio8/direction 12 | #gpio mode 8 out 13 | 14 | #echo "" 15 | #echo "Changing 27 direction to out" 16 | #echo out > /sys/class/gpio/gpio27/direction 17 | #cat /sys/class/gpio/gpio27/direction 18 | #gpio mode 27 out 19 | 20 | #echo "Setting output to low" 21 | #echo 0 > /sys/class/gpio/gpio8/value 22 | #cat /sys/class/gpio/gpio8/value 23 | #gpio write 8 0 24 | 25 | #echo "Reseting" 26 | #echo 0 > /sys/class/gpio/gpio27/value 27 | #echo 1 > /sys/class/gpio/gpio27/value 28 | #gpio write 27 0 29 | #gpio write 27 1 30 | 31 | #echo "Continuing with configuration procedure" 32 | dd if=$1 of=/dev/spidev0.0 33 | 34 | echo -e "\x0\x0\x0\x0\x0\x0\x0" > /dev/spidev0.0 35 | 36 | #echo "Setting output to high" 37 | #echo 1 > /sys/class/gpio/gpio8/value 38 | #cat /sys/class/gpio/gpio8/value 39 | #gpio write 8 1 40 | 41 | -------------------------------------------------------------------------------- /FPGA/pins.pcf: -------------------------------------------------------------------------------- 1 | # ############################################################################## 2 | 3 | # iCEcube PCF 4 | 5 | # Version: 2017.08.27940 6 | 7 | # File Generated: Mar 31 2019 12:09:07 8 | 9 | # Family & Device: iCE5LP4K 10 | 11 | # Package: SG48 12 | 13 | # ############################################################################## 14 | 15 | ###IOSet List 21 16 | set_io FPGA_PPS 23 17 | set_io pin_led16 46 18 | set_io AC_IN 20 19 | set_io TCXO_IN 35 20 | set_io EXT_IN 38 21 | set_io MI 14 22 | set_io NIXIE_CLK 11 23 | set_io pin_ledG 40 24 | set_io CS 27 25 | set_io NIXIE_DIN 13 26 | set_io NIXIE_LE 12 27 | set_io PWM_FAN 6 -pullup yes 28 | set_io PWM_FAN_INPUT 48 -pullup yes 29 | set_io pin_led15 47 30 | set_io pin_ledB 39 31 | set_io pin_ledR 41 32 | set_io vclk 44 33 | set_io GPS_PPS 32 34 | set_io MO 17 35 | set_io NIXIE_BL 9 36 | set_io NIXIE_POL 10 37 | set_io SCLK 15 38 | set_io FPGA_Counter_INT 21 39 | set_io GPS_TX 34 40 | set_io UART_DATA_INT 28 41 | set_io CS_uart 18 42 | set_io MAC_TX 36 43 | set_io MAC_RX 37 -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/README.md: -------------------------------------------------------------------------------- 1 | # Adafruit PCA9685 PWM Servo Driver Library ![Build Status](https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/workflows/Arduino%20Library%20CI/badge.svg) 2 | 3 | 4 | This is a library for our Adafruit 16-channel PWM & Servo driver, shield or FeatherWing 5 | 6 | 7 | 8 | Pick one up today in the adafruit shop! 9 | * https://www.adafruit.com/products/815 10 | * https://www.adafruit.com/product/1411 11 | * https://www.adafruit.com/product/2928 12 | 13 | These drivers use I2C to communicate, 2 pins are required to interface. 14 | 15 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 16 | 17 | Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, check license.txt for more information. 18 | 19 | All text above must be included in any redistribution 20 | -------------------------------------------------------------------------------- /FPGA/counter_test.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | 7 | 8 | module Counter_TestBench(); 9 | reg clock; 10 | initial clock = 0; 11 | 12 | always #(1) clock <= ~clock; 13 | wire rst; 14 | reg [2:0] resetn_counter = 0; 15 | always @(posedge clock) begin 16 | if (!rst) 17 | resetn_counter <= resetn_counter + 1; 18 | end 19 | assign rst = &resetn_counter; 20 | 21 | wire [31:0] counter; 22 | reg inputsig; 23 | initial inputsig = 0; 24 | CounterModule cm( 25 | .inputsig(inputsig), 26 | .clk(clock), 27 | .rst(rst), 28 | .falling_rising(1'b0), 29 | .counter(counter), 30 | .trigger() 31 | ); 32 | 33 | initial begin 34 | $dumpfile("Counter_TestBench.vcd"); 35 | $dumpvars(0, cm); 36 | $dumpvars(0, counter); 37 | #20 38 | inputsig <= 1; 39 | #200 40 | inputsig <= 1; 41 | #200 42 | inputsig <= 0; 43 | #200 44 | inputsig <= 1; 45 | #200 46 | inputsig <= 0; 47 | #50 48 | inputsig <= 1; 49 | #200 50 | inputsig <= 0; 51 | #200 52 | $finish; 53 | end 54 | 55 | endmodule -------------------------------------------------------------------------------- /FPGA/pdm_test.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | 7 | 8 | module SPI_TestBench(); 9 | reg clock; 10 | initial clock = 0; 11 | 12 | always #(1) clock <= ~clock; 13 | wire rst; 14 | reg [2:0] resetn_counter = 0; 15 | always @(posedge clock) begin 16 | if (!rst) 17 | resetn_counter <= resetn_counter + 1; 18 | end 19 | assign rst = &resetn_counter; 20 | 21 | reg [9:0] pwm_value; 22 | initial pwm_value = 0; 23 | wire PWM_out; 24 | pdm pdm( 25 | .clk(clock), 26 | .PWM_in(pwm_value), 27 | .divider(8'd2), 28 | .PWM_out(PWM_out), 29 | .pwm_write(1'b1), 30 | .pwm_div_write(1'b1), 31 | .rst(rst) 32 | ); 33 | 34 | 35 | 36 | initial begin 37 | $dumpfile("SPI_TestBench.vcd"); 38 | $dumpvars(0, pdm); 39 | $dumpvars(0, PWM_out); 40 | #20 41 | pwm_value <= 10; 42 | #20000 43 | pwm_value <= 255; 44 | #20000 45 | pwm_value <= 256; 46 | #20000 47 | pwm_value <= 511; 48 | #20000 49 | pwm_value <= 512; 50 | #20000 51 | pwm_value <= 1023; 52 | #20000 53 | $finish; 54 | end 55 | 56 | endmodule -------------------------------------------------------------------------------- /RPI_Code/readADC/parsebin.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear all 3 | 4 | fid = fopen('Waveform_20210828_155900.bin'); 5 | fseek(fid, 0, 'eof'); 6 | filesize = ftell(fid) 7 | fclose(fid); 8 | 9 | m = memmapfile('Waveform_20210828_155900.bin', ... 10 | 'Format', { ... 11 | 'uint32' [1 1] 'secondsOfDay'; ... 12 | 'uint32' [1 1] 'fifo'; ... 13 | 'uint16' [1 1] 'timestamp'; ... 14 | 'uint16' [1 1] 'adc_data'}, ... 15 | 'Repeat', filesize/12); 16 | 17 | 18 | T = struct2table(m.Data); 19 | m=1; 20 | 21 | timestamp = T.timestamp; 22 | seconds=0; 23 | time = cast(timestamp,'double')./50000; 24 | for i=1:size(timestamp,1) 25 | 26 | if timestamp(i) == 49999 27 | seconds = seconds + 1; 28 | end 29 | time(i) = time(i) + seconds; 30 | end 31 | %double voltage = ((double)adc_data - 32813.7864224796) * 0.001032546059765 -0.013938492775101; 32 | %ACMains_voltage = 8.81353422918265*VRMS_average + -3.41515186652297 33 | voltage = (cast(T.adc_data,'double') - 32813.7864224796) * 0.001032546059765 -0.013938492775101; 34 | AC = 8.81353422918265*voltage -3.41515186652297; 35 | plot(time,AC) -------------------------------------------------------------------------------- /FPGA/spi_m_test.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | 7 | 8 | module SPI_TestBench(); 9 | reg [7:0] data_in; 10 | wire [7:0] data_out; 11 | initial data_in = 0; 12 | 13 | reg clock; 14 | initial clock = 0; 15 | 16 | always #(1) clock <= ~clock; 17 | wire rst; 18 | 19 | wire SCK,MO,CS; 20 | reg data_in_valid,MI; 21 | initial data_in_valid = 0; 22 | initial MI = 0; 23 | wire data_out_valid; 24 | SPI_slave spi_s( 25 | .SCK(SCK), 26 | .MI(MI), 27 | .MO(MO), 28 | .CS(CS), 29 | .data_in(data_in), 30 | .data_in_valid(data_in_valid), 31 | .data_out(data_out), 32 | .data_out_valid(data_out_valid), 33 | .rst(rst), 34 | .clk(clock) 35 | ); 36 | 37 | reg [2:0] resetn_counter = 0; 38 | always @(posedge clock) begin 39 | if (!rst) 40 | resetn_counter <= resetn_counter + 1; 41 | end 42 | assign rst = &resetn_counter; 43 | 44 | initial begin 45 | $dumpfile("SPI_TestBench.vcd"); 46 | $dumpvars(0, spi_m); 47 | $dumpvars(0, data_out); 48 | #20 49 | data_in_valid <= 1; 50 | data_in <= 8'd55; 51 | #200 52 | $finish; 53 | end 54 | 55 | endmodule -------------------------------------------------------------------------------- /FPGA/pwm.v: -------------------------------------------------------------------------------- 1 | module pdm #(parameter NBITS = 16)( 2 | input clk, 3 | input [NBITS-1:0] PWM_in, 4 | input [NBITS-1:0] divider, 5 | output reg PWM_out, 6 | input pwm_write, 7 | input pwm_div_write, 8 | input rst 9 | ); 10 | 11 | reg [NBITS-1:0] pwm_value; 12 | reg [NBITS-1:0] pwm_divider; 13 | 14 | reg [NBITS-1:0] divided_counter; 15 | wire divided_clock = divided_counter == 0; 16 | 17 | reg [NBITS-1:0] error; 18 | reg [NBITS-1:0] error_0; 19 | reg [NBITS-1:0] error_1; 20 | 21 | always @(posedge clk) begin 22 | if (pwm_write) pwm_value <= PWM_in; 23 | if (pwm_div_write) pwm_divider <= divider; 24 | if (~rst) begin 25 | error <= 0; 26 | error_0 <= 0; 27 | error_1 <= 0; 28 | divided_counter <= 0; 29 | end 30 | else begin 31 | if(pwm_divider == divided_counter) begin 32 | divided_counter <= 0; 33 | end 34 | else begin 35 | divided_counter <= divided_counter + 1; 36 | end 37 | if(divided_clock) begin 38 | error_1 <= error + 2**NBITS - 1 - pwm_value; 39 | error_0 <= error - pwm_value; 40 | if (pwm_value >= error) begin 41 | PWM_out <= 1; 42 | error <= error_1; 43 | end 44 | else begin 45 | PWM_out <= 0; 46 | error <= error_0; 47 | end 48 | end 49 | end 50 | end 51 | endmodule -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2012, Adafruit Industries 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holders nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/examples/gpiotest/gpiotest.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for our Adafruit 16-channel PWM & Servo driver 3 | GPIO test - this will set a pin high/low 4 | 5 | Pick one up today in the adafruit shop! 6 | ------> http://www.adafruit.com/products/815 7 | 8 | These drivers use I2C to communicate, 2 pins are required to 9 | interface. 10 | 11 | Adafruit invests time and resources providing this open source code, 12 | please support Adafruit and open-source hardware by purchasing 13 | products from Adafruit! 14 | 15 | Written by Limor Fried/Ladyada for Adafruit Industries. 16 | BSD license, all text above must be included in any redistribution 17 | ****************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | // called this way, it uses the default address 0x40 23 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 24 | // you can also call it with a different address you want 25 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41); 26 | // you can also call it with a different address and I2C interface 27 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire); 28 | 29 | void setup() { 30 | Serial.begin(9600); 31 | Serial.println("GPIO test!"); 32 | 33 | pwm.begin(); 34 | pwm.setPWMFreq(1000); // Set to whatever you like, we don't use it in this demo! 35 | 36 | // if you want to really speed stuff up, you can go into 'fast 400khz I2C' mode 37 | // some i2c devices dont like this so much so if you're sharing the bus, watch 38 | // out for this! 39 | Wire.setClock(400000); 40 | } 41 | 42 | void loop() { 43 | // Drive each pin in a 'wave' 44 | for (uint8_t pin=0; pin<16; pin++) { 45 | pwm.setPWM(pin, 4096, 0); // turns pin fully on 46 | delay(100); 47 | pwm.setPWM(pin, 0, 4096); // turns pin fully off 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /FPGA/rtc.v: -------------------------------------------------------------------------------- 1 | module RTC( 2 | input clk, 3 | input rst, 4 | input pps, 5 | input [5:0] sec_in,min_in,hour_in, 6 | output [31:0] display_time, 7 | output [15:0] display_digit, 8 | output [5:0] sec_out,min_out,hour_out, 9 | input write_data 10 | ); 11 | 12 | reg [5:0] sec,min,hour; 13 | 14 | assign sec_out = sec; 15 | assign min_out = min; 16 | assign hour_out = hour; 17 | 18 | wire sec_overflow = (sec == 6'b111011); 19 | wire min_overflow = (min == 6'b111011) & sec_overflow; 20 | wire hour_overflow = (hour == 6'b10111) & min_overflow; 21 | 22 | assign display_digit = (sec%2 == 0) ? 16'b0000000000000000 : 16'b00100100_00000000; 23 | 24 | always @(posedge clk) begin 25 | if (~rst) begin 26 | sec <= 0; 27 | min <= 0; 28 | hour <= 0; 29 | end 30 | else begin 31 | if (write_data) begin 32 | sec <= sec_in; 33 | min <= min_in; 34 | hour <= hour_in; 35 | end 36 | else begin 37 | if (pps) begin 38 | sec <= sec +1; 39 | if (sec_overflow) begin 40 | sec <= 0; 41 | min <= min +1; 42 | end 43 | if (min_overflow) begin 44 | min <= 0; 45 | hour <= hour +1; 46 | end 47 | if (hour_overflow) begin 48 | hour <= 0; 49 | end 50 | end 51 | end 52 | end 53 | end 54 | 55 | wire [7:0] sec_bcd; 56 | wire [7:0] min_bcd; 57 | wire [7:0] hour_bcd; 58 | 59 | bin2bcd sec_conv(sec,sec_bcd); 60 | bin2bcd min_conv(min,min_bcd); 61 | bin2bcd hour_conv(hour,hour_bcd); 62 | 63 | // [8] [4] [8] [4] [8] 64 | //31 23 19 11 7 0 65 | assign display_time[31:24] = hour_bcd; 66 | assign display_time[19:12] = min_bcd; 67 | assign display_time[7:0] = sec_bcd; 68 | 69 | assign display_time[23:20] = 4'b1111; 70 | assign display_time[11:8] = 4'b1111; 71 | endmodule -------------------------------------------------------------------------------- /FPGA/README.md: -------------------------------------------------------------------------------- 1 | # Verilog Files 2 | 3 | Designed for iCE5LP 4 | 5 | ## File List 6 | * **main.v** - top verilog code 7 | * Driver 8 | * **ADS8681.v** - ADS8681 Driver 9 | * **tdc7200.v** - TDC7200 Driver 10 | * **nixie.v** - HV5623/HV5623 Driver 11 | * **spi_master.v** - SoftIP SPI, used by the Drivers 12 | * **spi_slave.v** - Using HardIP block 13 | * Utility 14 | * **coarsecounter.v** - Simple Counter 15 | * **bin2bcd.v** - Binary to BCD Code for Nixie Tube 16 | * **delayPPS.v** - Generate constant cycle delay for a given input signal 17 | * **fifo.v** - FIFO using BRAM blocks 18 | * **pps.v** - Generate PPS signal, and optionaly can align with external PPS 19 | * **pwm.v** - Actually it is generating PDM signal 20 | * **rtc.v** - A really simple RTC, just counting the time for Nixie Clock 21 | * Testbench 22 | * **counter_test.v** - coarsecounter.v testing 23 | * **pdm_test.v** - pwm.v testing 24 | * **spi_m_test.v** 25 | * **spi_s_test.v** 26 | * **pins.pcf** - pin definition 27 | 28 | ## iCECube2 output 29 | > Device Utilization Summary 30 | LogicCells : 2050/3520 31 | PLBs : 346/440 32 | BRAMs : 16/20 33 | IOs and GBIOs : 31/35 34 | PLLs : 0/1 35 | I2Cs : 0/2 36 | SPIs : 2/2 37 | DSPs : 0/4 38 | SBIOODs : 3/4 39 | LEDDRVs : 0/1 40 | RGBDRVs : 0/1 41 | IRDRVs : 0/1 42 | LEDDIPs : 0/1 43 | LFOSCs : 0/1 44 | HFOSCs : 1/1 45 | 46 | >Number of clocks: 5 47 | Clock: main|CLOCK | Frequency: 65.57 MHz | Target: 15.00 MHz 48 | Clock: main|SCK | Frequency: 394.30 MHz | Target: 15.00 MHz 49 | Clock: osc2.hfosc/CLKHF | Frequency: 113.89 MHz | Target: 48.00 MHz 50 | Clock: rpi_adc_dev.sb_spi_inst/SCKO | Frequency: N/A | Target: 25.00 MHz 51 | Clock: rpi_spi_dev.sb_spi_inst/SCKO | Frequency: N/A | Target: 25.00 MHz 52 | -------------------------------------------------------------------------------- /FPGA/delayPPS.v: -------------------------------------------------------------------------------- 1 | module delayPPS ( 2 | input clk, 3 | input pps_in, 4 | output pps_out, 5 | input rst 6 | ); 7 | localparam IDLE = 2'b00; 8 | localparam WAIT = 2'b01; 9 | localparam PULSE = 2'b10; 10 | 11 | //Delay the PPS for 300ms 12 | reg [19:0] delay_counter; 13 | reg [19:0] pulse_counter; 14 | 15 | reg [19:0] delay_counter_overflow; 16 | reg [19:0] pulse_counter_overflow; 17 | 18 | reg [1:0] currentState; 19 | reg [1:0] nextState; 20 | 21 | assign pps_out = (currentState == PULSE); 22 | 23 | reg pps_d; 24 | reg pps_d2; 25 | always @(posedge clk) begin 26 | pps_d <= pps_in; 27 | pps_d2 <= pps_d; 28 | if (!rst) begin 29 | currentState <= IDLE; 30 | delay_counter_overflow <= 20'h1386; 31 | pulse_counter_overflow <= 20'h1F4; 32 | delay_counter <= 0; 33 | pulse_counter <= 0; 34 | end 35 | else begin 36 | currentState <= nextState; 37 | case(currentState) 38 | IDLE: begin 39 | delay_counter <= 0; 40 | pulse_counter <= 0; 41 | end 42 | WAIT: begin 43 | delay_counter <= delay_counter + 1; 44 | end 45 | PULSE: begin 46 | pulse_counter <= pulse_counter + 1; 47 | end 48 | default: begin 49 | 50 | end 51 | endcase 52 | end 53 | end 54 | 55 | always @(*) begin 56 | nextState = currentState; 57 | case(currentState) 58 | IDLE: begin 59 | if(pps_d2 == 0 & pps_d == 1) begin 60 | nextState = WAIT; 61 | end 62 | end 63 | WAIT: begin 64 | if(delay_counter == delay_counter_overflow)begin 65 | nextState = PULSE; 66 | end 67 | end 68 | PULSE: begin 69 | if(pulse_counter == pulse_counter_overflow)begin 70 | nextState = IDLE; 71 | end 72 | end 73 | default: begin 74 | nextState = IDLE; 75 | end 76 | endcase 77 | end 78 | endmodule -------------------------------------------------------------------------------- /RPI_Code/fanControl.py: -------------------------------------------------------------------------------- 1 | from simple_pid import PID 2 | import time 3 | from adafruit_extended_bus import ExtendedI2C as I2C 4 | import adafruit_tmp117 5 | import os 6 | from influxdb import InfluxDBClient 7 | from threading import Event, Thread, Timer 8 | from multiprocessing import Queue 9 | import datetime 10 | from dbSetting import * 11 | 12 | time.sleep(10) 13 | 14 | dataQueue = Queue(300) 15 | 16 | class uploadDataThread (Thread): 17 | def __init__(self, ifuser, ifpass, ifdb, ifhost, queue): 18 | Thread.__init__(self) 19 | self.ifuser = ifuser 20 | self.ifpass = ifpass 21 | self.ifdb = ifdb 22 | self.ifhost = ifhost 23 | self.ifport = ifport 24 | self.queue = queue 25 | 26 | def run(self): 27 | print("[Upload Thread] Starting") 28 | self.ifclient = InfluxDBClient(ifhost,ifport,ifuser,ifpass,ifdb,timeout=2,retries=3) 29 | while 1: 30 | val = self.queue.get() 31 | try: 32 | self.ifclient.write_points(val) 33 | except Exception as e: 34 | print(e) 35 | 36 | uploadDataThread(ifuser, ifpass, ifdb, ifhost, dataQueue).start() 37 | 38 | 39 | i2c = I2C(0) 40 | #i2c = busio.I2C(board.SCL, board.SDA) 41 | tmp117 = adafruit_tmp117.TMP117(i2c, address=0x49) 42 | 43 | 44 | def write_fan(value): 45 | #print('i2cset -y 0 0x2f 0x30 '+ hex(value)) 46 | os.system('/usr/sbin/i2cset -y 0 0x2f 0x30 '+ hex(value)) 47 | 48 | os.system('/usr/sbin/i2cset -y 0 0x2f 0x31 0x01') 49 | pid = PID(Kp=-70, Ki=-1.5, Kd=0, setpoint=48) 50 | pid.sample_time = 0.5 51 | pid.output_limits = (10, 255) 52 | pid.set_auto_mode(True) 53 | # Assume we have a system we want to control in controlled_system 54 | v = tmp117.temperature 55 | 56 | while True: 57 | # Compute new output from the PID according to the systems current value 58 | control = pid(v) 59 | write_fan(int(control)) 60 | v = tmp117.temperature 61 | print('%f,%d' % (v,control)) 62 | body = [ 63 | { 64 | "measurement": "Fan", 65 | "time": datetime.datetime.utcnow(), 66 | "fields": { 67 | "Under Temperature": v, 68 | "FAN PWM": int(control) 69 | } 70 | } 71 | ] 72 | print(body) 73 | dataQueue.put(body) 74 | time.sleep(0.5) 75 | 76 | -------------------------------------------------------------------------------- /RPI_Code/README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Code 2 | 3 | The code is intended to document the communication with the FPGA and SA.3xm Atomic Clock. 4 | 5 | ## Setup 6 | 7 | ### Python Library 8 | ``` 9 | pip install -r requirements.txt 10 | ``` 11 | Library List: 12 | * influxdb Client 13 | * pyserial 14 | * simple_pid 15 | * adafruit-circuitpython-TMP117 16 | * python-dateutil 17 | 18 | ### GPS 19 | gpsd is not actually needed but I'm using it to parse some GPS NEMA data and connect to ntpd, so the program is designed around gpsd and take its serial dump and parse the UBX format phase error data. 20 | 21 | Note also you should enable UBX-TIM-TP output of the uBlox GPS module. 22 | 23 | ### InfluxDB 24 | InfluxDB is used to collect time series data. The setting is in **dbSetting.py** 25 | 26 | ## Code List 27 | 28 | * **uploadClock.py** 29 | * The main program to communicate with FPGA 30 | * Reading FPGA data, including TDC7200 measurement 31 | * Setting up FPGA time and inital PPS alignment 32 | * Reading GPS Serial data from stdin and calculate corrected PPS error 33 | * Nixie Tube animate to prevent cathode poisoning 34 | * **uploadMAC.py** 35 | * Reading MAC status and creating UDP server for other program to communicate with MAC. (**calibrateClock.py**) 36 | * **calibrateClock.py** 37 | * The program to read current PPS error using InfluxDB and tune the clock EFC. The EFC tuning cmd is send via UDP package to **uploadMAC.py**. The tuning algroithm is a simple accumlated error. 38 | * **readADC** 39 | * The C program to poll ADC reading and output frequency and Vrms data to stdio. 40 | * `gcc -o readADC ./readADC.c -lm -mcpu='cortex-a72' -O3` 41 | * `./readADC [folderPath]` 42 | * **autoBrightness** 43 | * The C program to control Nixie Tube brightness. Reading Lux sensor and send cmd to FPGA. 44 | * `g++ -o autoBrightness ./main.cpp ./Adafruit_PWMServoDriver.cpp ./TSL2561.cpp -lwiringPi` 45 | * `autoBrightness [lowest_pwm]` 46 | * **fanControl.py** 47 | * Reading TMP117 and using PID loop on the bottom fan to maintain the clock temperature 48 | * mountdrive.sh 49 | * Creating a 512MB ramdisk to store AC waveform, and mounting NVMe drive. 50 | * **moveFile.py** 51 | * Copy the file from ramdisk to NVMe drive. 52 | * **uploadFPGA.py** 53 | * Uploading FPGA bin file via SPI 54 | * **uploadFPGA.sh** 55 | * The helper shell script of **uploadFPGA.py** 56 | * **dbSetting.py** 57 | * The settings for InfluxDB location 58 | 59 | -------------------------------------------------------------------------------- /FPGA/fifo.v: -------------------------------------------------------------------------------- 1 | module fifo #( 2 | parameter data_width = 8, 3 | parameter fifo_depth = 32, 4 | parameter addr_width = $clog2(fifo_depth)) ( 5 | input clk, rst, 6 | 7 | // Write side 8 | input wr_en, 9 | input [data_width-1:0] din, 10 | output full, 11 | 12 | // Read side 13 | input rd_en, 14 | output [data_width-1:0] dout, 15 | output empty, 16 | 17 | output avail, 18 | output [addr_width:0] count 19 | ); 20 | 21 | localparam ADDR_W=addr_width; 22 | localparam DATA_W=data_width; 23 | localparam DEPTH=fifo_depth; 24 | 25 | localparam [ADDR_W-1:0] ADDR_LIMIT=DEPTH-1; 26 | reg [ADDR_W-1:0] addr_re=0; // Read pointer 27 | reg [ADDR_W-1:0] addr_wr=0; // Write pointer 28 | reg [ADDR_W:0] diff=0; // [0;DEPTH] => +1 29 | wire avail_now; 30 | reg avail_ff; 31 | 32 | assign count = diff; 33 | // FIFO RAM 34 | reg [DATA_W-1:0] ram[DEPTH-1:0]; 35 | reg [ADDR_W-1:0] read_addr_r=0; 36 | // memory process 37 | always @(posedge clk) begin 38 | if (wr_en) 39 | ram[addr_wr] <= din; 40 | read_addr_r <= addr_re; 41 | end 42 | assign dout=ram[read_addr_r]; 43 | 44 | // Use delay for avail_now signal rising edge 45 | always @(posedge clk) 46 | begin : avail_ff_proc 47 | if (~rst) 48 | avail_ff <= 1'b0; 49 | else 50 | avail_ff <= avail_now; 51 | end // avail_ff_proc 52 | assign avail_now=diff!=0; 53 | // Avail signal output 54 | assign avail=avail_now & avail_ff; 55 | 56 | assign full=diff==DEPTH; 57 | //assign used=diff; 58 | 59 | always @(posedge clk) 60 | begin : FIFO_work 61 | if (~rst) 62 | begin 63 | addr_wr <= 0; 64 | addr_re <= 0; 65 | diff <= 0; 66 | end 67 | else 68 | begin 69 | if (wr_en) // Write to the FIFO. 70 | begin 71 | if (addr_wr==ADDR_LIMIT) 72 | addr_wr <= 0; 73 | else 74 | addr_wr <= addr_wr+1; 75 | diff <= diff+1; 76 | end 77 | if (rd_en) // Read to the FIFO. 78 | begin 79 | if (addr_re==ADDR_LIMIT) 80 | addr_re <= 0; 81 | else 82 | addr_re <= addr_re+1; 83 | diff <= diff-1; 84 | end 85 | // Concurrent read and write, we increment and decrement, so we 86 | // let diff unchanged. 87 | if (rd_en && wr_en) 88 | diff <= diff; 89 | end 90 | end // FIFO_work 91 | 92 | assign empty=~avail_now; 93 | endmodule 94 | -------------------------------------------------------------------------------- /RPI_Code/calibrateClock.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | from influxdb import InfluxDBClient 4 | import time 5 | import datetime 6 | from multiprocessing import Queue 7 | from threading import Event, Thread, Timer 8 | from dbSetting import * 9 | from simple_pid import PID 10 | 11 | query_where2 = 'SELECT mean("Adjusted Clock") FROM "FPGA" WHERE time > now() - 12h' 12 | #query_where = 'SELECT mean("PPS Duration") FROM "FPGA" WHERE time > now() - 2h' 13 | query_where = 'SELECT "Adjusted Clock" FROM "FPGA" WHERE time > now() - 2s' 14 | 15 | # Create a UDP socket 16 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 17 | server_address = ('localhost', 10000) 18 | sock.settimeout(0.5) 19 | 20 | ifclient = InfluxDBClient(ifhost,ifport,ifuser,ifpass,ifdb,timeout=2,retries=3) 21 | 22 | #pid = PID(Kp=0, Ki=300, Kd=0, setpoint=0) 23 | #pid.sample_time = 1 24 | 25 | accumlated_error = 0 26 | 27 | def call_repeatedly(interval, func, *args): 28 | stopped = Event() 29 | print("[call_repeatedly] Starting") 30 | def loop(): 31 | while not stopped.wait(interval - time.time() % interval): # the first call is in `interval` secs 32 | func(*args) 33 | Thread(target=loop).start() 34 | return stopped.set 35 | 36 | def readData(): 37 | #global pid 38 | global accumlated_error 39 | 40 | try: 41 | result = ifclient.query(query_where) 42 | result2 = ifclient.query(query_where2) 43 | Average = list(result2.get_points())[0] 44 | #averageDataPoint = list(result.get_points())[0] 45 | averageDataPoint = float((list(result.get_points())[-1]['Adjusted Clock'])) 46 | error = averageDataPoint - 10000000 47 | #error = averageDataPoint['mean'] - 10000000 48 | #control = pid(error) 49 | #print(pid.components) 50 | accumlated_error += error 51 | control = -1*accumlated_error*300 52 | print("control:%f"%control) 53 | cmd = "" 54 | cmd = cmd.encode() 55 | print("CMD:%s"%cmd) 56 | sent = sock.sendto(cmd, server_address) 57 | data, server = sock.recvfrom(4096) 58 | print("Received:%s"%data) 59 | print("Error:%f, accumlated_error:%f, Control:%f "%(error, accumlated_error,control)) 60 | except Exception as e: 61 | print(e) 62 | pass 63 | 64 | 65 | cmd = "" 66 | cmd = cmd.encode() 67 | sent = sock.sendto(cmd, server_address) 68 | data, server = sock.recvfrom(4096) 69 | print("Received:%s"%data) 70 | 71 | time.sleep(1-time.time()%1) 72 | cancel_future_calls = call_repeatedly(1, readData) 73 | 74 | try: 75 | while 1: 76 | time.sleep(10000) 77 | pass 78 | except KeyboardInterrupt: 79 | sys.exit() 80 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/examples/tsl2561/tsl2561.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "TSL2561.h" 3 | 4 | // Example for demonstrating the TSL2561 library - public domain! 5 | 6 | // connect SCL to analog 5 7 | // connect SDA to analog 4 8 | // connect VDD to 3.3V DC 9 | // connect GROUND to common ground 10 | // ADDR can be connected to ground, or vdd or left floating to change the i2c address 11 | 12 | // The address will be different depending on whether you let 13 | // the ADDR pin float (addr 0x39), or tie it to ground or vcc. In those cases 14 | // use TSL2561_ADDR_LOW (0x29) or TSL2561_ADDR_HIGH (0x49) respectively 15 | TSL2561 tsl(TSL2561_ADDR_FLOAT); 16 | 17 | void setup(void) { 18 | Serial.begin(9600); 19 | 20 | if (tsl.begin()) { 21 | Serial.println("Found sensor"); 22 | } else { 23 | Serial.println("No sensor?"); 24 | while (1); 25 | } 26 | 27 | // You can change the gain on the fly, to adapt to brighter/dimmer light situations 28 | //tsl.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations) 29 | tsl.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations) 30 | 31 | // Changing the integration time gives you a longer time over which to sense light 32 | // longer timelines are slower, but are good in very low light situtations! 33 | tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright light) 34 | //tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light) 35 | //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim light) 36 | 37 | // Now we're ready to get readings! 38 | } 39 | 40 | void loop(void) { 41 | // Simple data read example. Just read the infrared, fullspecrtrum diode 42 | // or 'visible' (difference between the two) channels. 43 | // This can take 13-402 milliseconds! Uncomment whichever of the following you want to read 44 | uint16_t x = tsl.getLuminosity(TSL2561_VISIBLE); 45 | //uint16_t x = tsl.getLuminosity(TSL2561_FULLSPECTRUM); 46 | //uint16_t x = tsl.getLuminosity(TSL2561_INFRARED); 47 | 48 | Serial.println(x, DEC); 49 | 50 | // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum 51 | // That way you can do whatever math and comparisons you want! 52 | uint32_t lum = tsl.getFullLuminosity(); 53 | uint16_t ir, full; 54 | ir = lum >> 16; 55 | full = lum & 0xFFFF; 56 | Serial.print("IR: "); Serial.print(ir); Serial.print("\t\t"); 57 | Serial.print("Full: "); Serial.print(full); Serial.print("\t"); 58 | Serial.print("Visible: "); Serial.print(full - ir); Serial.print("\t"); 59 | 60 | Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir)); 61 | 62 | delay(100); 63 | } 64 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /FPGA/spi_s_test.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `define SECOND 1000000000 4 | `define MS 1000000 5 | 6 | 7 | 8 | module SPI_TestBench(); 9 | wire [7:0] data_in; 10 | reg [7:0] data_out; 11 | initial data_out = 0; 12 | 13 | reg [7:0]testdata; 14 | initial testdata = 8'h1275; 15 | 16 | reg clock; 17 | initial clock = 0; 18 | 19 | always #(1) clock <= ~clock; 20 | wire rst; 21 | 22 | reg SCK,MO,CS; 23 | wire MI; 24 | initial SCK = 1; 25 | initial MO = 0; 26 | initial CS = 1; 27 | 28 | SPI_slave rpi_spi_dev( 29 | .clk(clock), 30 | .SCK(SCK), 31 | .MOSI(MO), 32 | .MISO(MI), 33 | .SSEL(CS), 34 | .LED(), 35 | .byte_data_received(data_in), 36 | .byte_received(byte_received), 37 | .byte_sent(data_out) 38 | ); 39 | 40 | reg [2:0] resetn_counter = 0; 41 | always @(posedge clock) begin 42 | if (!rst) 43 | resetn_counter <= resetn_counter + 1; 44 | end 45 | assign rst = &resetn_counter; 46 | 47 | 48 | reg [31:0] registers [7:0]; 49 | reg [31:0] rpi_out; 50 | wire [39:0] data_in; 51 | wire rw_select = data_in[7]; 52 | wire [31:0]rpi_data_in = data_in[39:8]; 53 | wire [6:0] rpi_address = data_in[6:0]; 54 | wire rpi_byte_received; 55 | 56 | always @(posedge clock) begin 57 | if (!rst) begin 58 | registers <= 0; 59 | end 60 | else 61 | if(rpi_byte_received & rw_select) begin 62 | registers[rpi_address] <= rpi_data_in; 63 | end 64 | else if(rpi_byte_received & ~rw_select) begin 65 | rpi_out <= registers[rpi_address]; 66 | end 67 | end 68 | end 69 | 70 | initial begin 71 | $dumpfile("SPI_TestBench.vcd"); 72 | $dumpvars(0, rpi_spi_dev); 73 | $dumpvars(0, rpi_out); 74 | $dumpvars(0, registers); 75 | #20 76 | CS <= 0; 77 | #1 78 | SCK <= 0; 79 | 80 | #3 81 | MO <= 1; 82 | SCK <= 0; 83 | #3 84 | SCK <= 1; 85 | 86 | #3 87 | MO <= 1; 88 | SCK <= 0; 89 | #3 90 | SCK <= 1; 91 | 92 | #3 93 | MO <= 0; 94 | SCK <= 0; 95 | #3 96 | SCK <= 1; 97 | 98 | #3 99 | MO <= 1; 100 | SCK <= 0; 101 | #3 102 | SCK <= 1; 103 | 104 | #3 105 | MO <= 1; 106 | SCK <= 0; 107 | #3 108 | SCK <= 1; 109 | 110 | #3 111 | MO <= 1; 112 | SCK <= 0; 113 | #3 114 | SCK <= 1; 115 | 116 | #3 117 | MO <= 0; 118 | SCK <= 0; 119 | #3 120 | SCK <= 1; 121 | 122 | #3 123 | MO <= 1; 124 | SCK <= 0; 125 | #3 126 | SCK <= 1; 127 | 128 | #3 129 | CS <= 1; 130 | #3 131 | SCK <= 1; 132 | 133 | #200 134 | $finish; 135 | end 136 | 137 | endmodule -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/examples/pwmtest/pwmtest.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for our Adafruit 16-channel PWM & Servo driver 3 | PWM test - this will drive 16 PWMs in a 'wave' 4 | 5 | Pick one up today in the adafruit shop! 6 | ------> http://www.adafruit.com/products/815 7 | 8 | These drivers use I2C to communicate, 2 pins are required to 9 | interface. 10 | 11 | Adafruit invests time and resources providing this open source code, 12 | please support Adafruit and open-source hardware by purchasing 13 | products from Adafruit! 14 | 15 | Written by Limor Fried/Ladyada for Adafruit Industries. 16 | BSD license, all text above must be included in any redistribution 17 | ****************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | // called this way, it uses the default address 0x40 23 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 24 | // you can also call it with a different address you want 25 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41); 26 | // you can also call it with a different address and I2C interface 27 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire); 28 | 29 | void setup() { 30 | Serial.begin(9600); 31 | Serial.println("16 channel PWM test!"); 32 | 33 | pwm.begin(); 34 | /* 35 | * In theory the internal oscillator (clock) is 25MHz but it really isn't 36 | * that precise. You can 'calibrate' this by tweaking this number until 37 | * you get the PWM update frequency you're expecting! 38 | * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and 39 | * is used for calculating things like writeMicroseconds() 40 | * Analog servos run at ~50 Hz updates, It is importaint to use an 41 | * oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip. 42 | * 1) Attach the oscilloscope to one of the PWM signal pins and ground on 43 | * the I2C PCA9685 chip you are setting the value for. 44 | * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the 45 | * expected value (50Hz for most ESCs) 46 | * Setting the value here is specific to each individual I2C PCA9685 chip and 47 | * affects the calculations for the PWM update frequency. 48 | * Failure to correctly set the int.osc value will cause unexpected PWM results 49 | */ 50 | pwm.setOscillatorFrequency(27000000); 51 | pwm.setPWMFreq(1600); // This is the maximum PWM frequency 52 | 53 | // if you want to really speed stuff up, you can go into 'fast 400khz I2C' mode 54 | // some i2c devices dont like this so much so if you're sharing the bus, watch 55 | // out for this! 56 | Wire.setClock(400000); 57 | } 58 | 59 | void loop() { 60 | // Drive each PWM in a 'wave' 61 | for (uint16_t i=0; i<4096; i += 8) { 62 | for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) { 63 | pwm.setPWM(pwmnum, 0, (i + (4096/16)*pwmnum) % 4096 ); 64 | } 65 | #ifdef ESP8266 66 | yield(); // take a breather, required for ESP8266 67 | #endif 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /FPGA/spi_master.v: -------------------------------------------------------------------------------- 1 | module SPI_MASTER ( 2 | output reg SCK, 3 | input MI, 4 | output MO, 5 | output reg CS, 6 | input [31:0] data_in, 7 | input data_in_valid, 8 | output [31:0] data_out, 9 | output reg data_out_valid, 10 | input rst, 11 | input clk, 12 | input [6:0]bitCount 13 | ); 14 | 15 | localparam IDLE = 3'b000; 16 | localparam SHIFT_0 = 3'b001; 17 | localparam SHIFT_1 = 3'b010; 18 | localparam START_0 = 3'b011; 19 | localparam START_1 = 3'b100; 20 | localparam END = 3'b101; 21 | 22 | reg [2:0] currentState; 23 | reg [2:0] nextState; 24 | 25 | reg [4:0] dataCounter; 26 | reg [15:0] dataInStored; 27 | reg [31:0] dataOutStored; 28 | 29 | reg [1:0] data_in_valid_d; 30 | 31 | assign MO = dataInStored[15]; // send MSB first 32 | assign data_out = dataOutStored; 33 | always @(posedge clk) begin 34 | data_in_valid_d <= {data_in_valid_d[0],data_in_valid}; 35 | if (!rst) begin 36 | currentState <= IDLE; 37 | SCK <= 0; 38 | CS <= 1; 39 | dataOutStored <= 0; 40 | dataCounter <= 0; 41 | dataInStored <= 0; 42 | end 43 | else begin 44 | currentState <= nextState; 45 | case(currentState) 46 | IDLE: begin 47 | if(data_in_valid) begin 48 | dataInStored <= data_in; 49 | dataCounter <= 0; 50 | end 51 | CS <= 1; 52 | SCK <= 0; 53 | end 54 | START_0: begin 55 | CS <= 0; 56 | SCK <= 0; 57 | end 58 | START_1: begin 59 | CS <= 0; 60 | SCK <= 1; 61 | end 62 | SHIFT_0: begin 63 | CS <= 0; 64 | dataOutStored <= {dataOutStored[31:0], MI}; 65 | SCK <= 1; 66 | end 67 | SHIFT_1: begin 68 | CS <= 0; 69 | dataCounter <= dataCounter + 1; 70 | dataInStored <= {dataInStored[14:0], 1'b0}; 71 | SCK <= 0; 72 | end 73 | END: begin 74 | CS <= 1; 75 | SCK <= 0; 76 | end 77 | default: begin 78 | 79 | end 80 | endcase 81 | end 82 | end 83 | 84 | always @(*) begin 85 | nextState = currentState; 86 | case(currentState) 87 | IDLE: begin 88 | if(data_in_valid_d == 2'b01) begin 89 | nextState = START_0; 90 | end 91 | data_out_valid = 0; 92 | end 93 | START_0: begin 94 | nextState = START_1; 95 | end 96 | START_1: begin 97 | nextState = SHIFT_0; 98 | end 99 | SHIFT_0: begin 100 | nextState = SHIFT_1; 101 | end 102 | SHIFT_1: begin 103 | if(dataCounter == bitCount)begin 104 | nextState = END; 105 | end 106 | else begin 107 | nextState = SHIFT_0; 108 | end 109 | end 110 | END: begin 111 | nextState = IDLE; 112 | data_out_valid = 1; 113 | end 114 | default: begin 115 | nextState = IDLE; 116 | end 117 | endcase 118 | end 119 | endmodule -------------------------------------------------------------------------------- /RPI_Code/uploadMAC.py: -------------------------------------------------------------------------------- 1 | import time 2 | import math 3 | import datetime 4 | from influxdb import InfluxDBClient 5 | from threading import Event, Thread, Timer 6 | from multiprocessing import Queue 7 | import serial 8 | import socket 9 | import sys 10 | from dbSetting import * 11 | 12 | # Create a UDP socket 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 14 | 15 | # Bind the socket to the port 16 | server_address = ('localhost', 10000) 17 | print('starting up on {} port {}'.format(*server_address)) 18 | sock.bind(server_address) 19 | 20 | 21 | ser = serial.Serial('/dev/ttyAMA1',57600,timeout=1) 22 | 23 | serialLock = False 24 | 25 | dataQueue = Queue(300) 26 | 27 | class uploadDataThread (Thread): 28 | def __init__(self, ifuser, ifpass, ifdb, ifhost, queue): 29 | Thread.__init__(self) 30 | self.ifuser = ifuser 31 | self.ifpass = ifpass 32 | self.ifdb = ifdb 33 | self.ifhost = ifhost 34 | self.ifport = ifport 35 | self.queue = queue 36 | 37 | def run(self): 38 | print("[Upload Thread] Starting") 39 | self.ifclient = InfluxDBClient(ifhost,ifport,ifuser,ifpass,ifdb,timeout=2,retries=3) 40 | while 1: 41 | val = self.queue.get() 42 | try: 43 | self.ifclient.write_points(val) 44 | except Exception as e: 45 | print(e) 46 | 47 | uploadDataThread(ifuser, ifpass, ifdb, ifhost, dataQueue).start() 48 | 49 | 50 | 51 | def call_repeatedly(interval, func, *args): 52 | stopped = Event() 53 | print("[call_repeatedly] Starting") 54 | def loop(): 55 | while not stopped.wait(interval - time.time() % interval): # the first call is in `interval` secs 56 | func(*args) 57 | Thread(target=loop).start() 58 | return stopped.set 59 | 60 | 61 | def readData(): 62 | global serialLock 63 | while serialLock: 64 | time.sleep(0.01) 65 | try: 66 | time.sleep(0.5) 67 | serialLock = True 68 | ser.flushInput() 69 | ser.write(b'^') 70 | line = ser.readline() 71 | serialLock = False 72 | line = line.decode("utf-8").strip('\r\n') 73 | print(line) 74 | data = line.split(',') 75 | body = [ 76 | { 77 | "measurement": "MAC", 78 | "time": datetime.datetime.utcnow(), 79 | "fields": { 80 | "BITE": int(data[0]), 81 | "Version": data[1], 82 | "SerialNumber": data[2], 83 | "TEC Control": int(data[3])/1000, 84 | "RF Control": int(data[4])/10, 85 | "DDS Frequency Center Current": int(data[5])/100, 86 | "CellHeaterCurrent": int(data[6]), 87 | "DCSignal": int(data[7]), 88 | "Temperature": int(data[8])/1000, 89 | "Digital Tuning": int(data[9]), 90 | "Analog Tuning On/Off": int(data[10]), 91 | "Analog Tuning": int(data[11]) 92 | } 93 | } 94 | ] 95 | print(body) 96 | dataQueue.put(body) 97 | except Exception as e: 98 | print(e) 99 | pass 100 | 101 | cancel_future_calls = call_repeatedly(1, readData) 102 | 103 | try: 104 | ser.flushInput() 105 | while 1: 106 | try: 107 | print('\nwaiting to receive message') 108 | data, address = sock.recvfrom(4096) 109 | print('<===received {} bytes from {}'.format(len(data), address)) 110 | print(data) 111 | while serialLock: 112 | time.sleep(0.01) 113 | serialLock = True 114 | ser.write(data) 115 | line = ser.readline() 116 | print("==>Send:%s"%line) 117 | sent = sock.sendto(line, address) 118 | serialLock = False 119 | pass 120 | except Exception as e: 121 | print(e) 122 | serialLock = False 123 | pass 124 | except KeyboardInterrupt: 125 | sys.exit() 126 | 127 | 128 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit_PWMServoDriver.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_PWMServoDriver.h 3 | * 4 | * This is a library for our Adafruit 16-channel PWM & Servo driver. 5 | * 6 | * Designed specifically to work with the Adafruit 16-channel PWM & Servo 7 | * driver. 8 | * 9 | * Pick one up today in the adafruit shop! 10 | * ------> https://www.adafruit.com/product/815 11 | * 12 | * These driver use I2C to communicate, 2 pins are required to interface. 13 | * For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4. 14 | * 15 | * Adafruit invests time and resources providing this open source code, 16 | * please support Adafruit andopen-source hardware by purchasing products 17 | * from Adafruit! 18 | * 19 | * Limor Fried/Ladyada (Adafruit Industries). 20 | * 21 | * BSD license, all text above must be included in any redistribution 22 | */ 23 | #ifndef _ADAFRUIT_PWMServoDriver_H 24 | #define _ADAFRUIT_PWMServoDriver_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | // REGISTER ADDRESSES 34 | #define PCA9685_MODE1 0x00 /**< Mode Register 1 */ 35 | #define PCA9685_MODE2 0x01 /**< Mode Register 2 */ 36 | #define PCA9685_SUBADR1 0x02 /**< I2C-bus subaddress 1 */ 37 | #define PCA9685_SUBADR2 0x03 /**< I2C-bus subaddress 2 */ 38 | #define PCA9685_SUBADR3 0x04 /**< I2C-bus subaddress 3 */ 39 | #define PCA9685_ALLCALLADR 0x05 /**< LED All Call I2C-bus address */ 40 | #define PCA9685_LED0_ON_L 0x06 /**< LED0 on tick, low byte*/ 41 | #define PCA9685_LED0_ON_H 0x07 /**< LED0 on tick, high byte*/ 42 | #define PCA9685_LED0_OFF_L 0x08 /**< LED0 off tick, low byte */ 43 | #define PCA9685_LED0_OFF_H 0x09 /**< LED0 off tick, high byte */ 44 | // etc all 16: LED15_OFF_H 0x45 45 | #define PCA9685_ALLLED_ON_L 0xFA /**< load all the LEDn_ON registers, low */ 46 | #define PCA9685_ALLLED_ON_H 0xFB /**< load all the LEDn_ON registers, high */ 47 | #define PCA9685_ALLLED_OFF_L 0xFC /**< load all the LEDn_OFF registers, low */ 48 | #define PCA9685_ALLLED_OFF_H 0xFD /**< load all the LEDn_OFF registers,high */ 49 | #define PCA9685_PRESCALE 0xFE /**< Prescaler for PWM output frequency */ 50 | #define PCA9685_TESTMODE 0xFF /**< defines the test mode to be entered */ 51 | 52 | // MODE1 bits 53 | #define MODE1_ALLCAL 0x01 /**< respond to LED All Call I2C-bus address */ 54 | #define MODE1_SUB3 0x02 /**< respond to I2C-bus subaddress 3 */ 55 | #define MODE1_SUB2 0x04 /**< respond to I2C-bus subaddress 2 */ 56 | #define MODE1_SUB1 0x08 /**< respond to I2C-bus subaddress 1 */ 57 | #define MODE1_SLEEP 0x10 /**< Low power mode. Oscillator off */ 58 | #define MODE1_AI 0x20 /**< Auto-Increment enabled */ 59 | #define MODE1_EXTCLK 0x40 /**< Use EXTCLK pin clock */ 60 | #define MODE1_RESTART 0x80 /**< Restart enabled */ 61 | // MODE2 bits 62 | #define MODE2_OUTNE_0 0x01 /**< Active LOW output enable input */ 63 | #define MODE2_OUTNE_1 \ 64 | 0x02 /**< Active LOW output enable input - high impedience */ 65 | #define MODE2_OUTDRV 0x04 /**< totem pole structure vs open-drain */ 66 | #define MODE2_OCH 0x08 /**< Outputs change on ACK vs STOP */ 67 | #define MODE2_INVRT 0x10 /**< Output logic state inverted */ 68 | 69 | #define PCA9685_I2C_ADDRESS 0x40 /**< Default PCA9685 I2C Slave Address */ 70 | #define FREQUENCY_OSCILLATOR 25000000 /**< Int. osc. frequency in datasheet */ 71 | 72 | #define PCA9685_PRESCALE_MIN 3 /**< minimum prescale value */ 73 | #define PCA9685_PRESCALE_MAX 255 /**< maximum prescale value */ 74 | 75 | /*! 76 | * @brief Class that stores state and functions for interacting with PCA9685 77 | * PWM chip 78 | */ 79 | class Adafruit_PWMServoDriver { 80 | public: 81 | Adafruit_PWMServoDriver(const uint8_t addr); 82 | void begin(uint8_t prescale = 0); 83 | void reset(); 84 | void sleep(); 85 | void wakeup(); 86 | void setExtClk(uint8_t prescale); 87 | void setPWMFreq(float freq); 88 | void setOutputMode(bool totempole); 89 | uint8_t getPWM(uint8_t num); 90 | void setPWM(uint8_t num, uint16_t on, uint16_t off); 91 | void setPin(uint8_t num, uint16_t val, bool invert = false); 92 | uint8_t readPrescale(void); 93 | void writeMicroseconds(uint8_t num, uint16_t Microseconds); 94 | 95 | void setOscillatorFrequency(uint32_t freq); 96 | uint32_t getOscillatorFrequency(void); 97 | 98 | private: 99 | uint8_t _i2caddr; 100 | int _fd; 101 | 102 | uint32_t _oscillator_freq; 103 | uint8_t read8(uint8_t addr); 104 | void write8(uint8_t addr, uint8_t d); 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/Adafruit_PWMServoDriver.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_PWMServoDriver.h 3 | * 4 | * This is a library for our Adafruit 16-channel PWM & Servo driver. 5 | * 6 | * Designed specifically to work with the Adafruit 16-channel PWM & Servo 7 | * driver. 8 | * 9 | * Pick one up today in the adafruit shop! 10 | * ------> https://www.adafruit.com/product/815 11 | * 12 | * These driver use I2C to communicate, 2 pins are required to interface. 13 | * For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4. 14 | * 15 | * Adafruit invests time and resources providing this open source code, 16 | * please support Adafruit andopen-source hardware by purchasing products 17 | * from Adafruit! 18 | * 19 | * Limor Fried/Ladyada (Adafruit Industries). 20 | * 21 | * BSD license, all text above must be included in any redistribution 22 | */ 23 | #ifndef _ADAFRUIT_PWMServoDriver_H 24 | #define _ADAFRUIT_PWMServoDriver_H 25 | 26 | #include 27 | #include 28 | 29 | // REGISTER ADDRESSES 30 | #define PCA9685_MODE1 0x00 /**< Mode Register 1 */ 31 | #define PCA9685_MODE2 0x01 /**< Mode Register 2 */ 32 | #define PCA9685_SUBADR1 0x02 /**< I2C-bus subaddress 1 */ 33 | #define PCA9685_SUBADR2 0x03 /**< I2C-bus subaddress 2 */ 34 | #define PCA9685_SUBADR3 0x04 /**< I2C-bus subaddress 3 */ 35 | #define PCA9685_ALLCALLADR 0x05 /**< LED All Call I2C-bus address */ 36 | #define PCA9685_LED0_ON_L 0x06 /**< LED0 on tick, low byte*/ 37 | #define PCA9685_LED0_ON_H 0x07 /**< LED0 on tick, high byte*/ 38 | #define PCA9685_LED0_OFF_L 0x08 /**< LED0 off tick, low byte */ 39 | #define PCA9685_LED0_OFF_H 0x09 /**< LED0 off tick, high byte */ 40 | // etc all 16: LED15_OFF_H 0x45 41 | #define PCA9685_ALLLED_ON_L 0xFA /**< load all the LEDn_ON registers, low */ 42 | #define PCA9685_ALLLED_ON_H 0xFB /**< load all the LEDn_ON registers, high */ 43 | #define PCA9685_ALLLED_OFF_L 0xFC /**< load all the LEDn_OFF registers, low */ 44 | #define PCA9685_ALLLED_OFF_H 0xFD /**< load all the LEDn_OFF registers,high */ 45 | #define PCA9685_PRESCALE 0xFE /**< Prescaler for PWM output frequency */ 46 | #define PCA9685_TESTMODE 0xFF /**< defines the test mode to be entered */ 47 | 48 | // MODE1 bits 49 | #define MODE1_ALLCAL 0x01 /**< respond to LED All Call I2C-bus address */ 50 | #define MODE1_SUB3 0x02 /**< respond to I2C-bus subaddress 3 */ 51 | #define MODE1_SUB2 0x04 /**< respond to I2C-bus subaddress 2 */ 52 | #define MODE1_SUB1 0x08 /**< respond to I2C-bus subaddress 1 */ 53 | #define MODE1_SLEEP 0x10 /**< Low power mode. Oscillator off */ 54 | #define MODE1_AI 0x20 /**< Auto-Increment enabled */ 55 | #define MODE1_EXTCLK 0x40 /**< Use EXTCLK pin clock */ 56 | #define MODE1_RESTART 0x80 /**< Restart enabled */ 57 | // MODE2 bits 58 | #define MODE2_OUTNE_0 0x01 /**< Active LOW output enable input */ 59 | #define MODE2_OUTNE_1 \ 60 | 0x02 /**< Active LOW output enable input - high impedience */ 61 | #define MODE2_OUTDRV 0x04 /**< totem pole structure vs open-drain */ 62 | #define MODE2_OCH 0x08 /**< Outputs change on ACK vs STOP */ 63 | #define MODE2_INVRT 0x10 /**< Output logic state inverted */ 64 | 65 | #define PCA9685_I2C_ADDRESS 0x40 /**< Default PCA9685 I2C Slave Address */ 66 | #define FREQUENCY_OSCILLATOR 25000000 /**< Int. osc. frequency in datasheet */ 67 | 68 | #define PCA9685_PRESCALE_MIN 3 /**< minimum prescale value */ 69 | #define PCA9685_PRESCALE_MAX 255 /**< maximum prescale value */ 70 | 71 | /*! 72 | * @brief Class that stores state and functions for interacting with PCA9685 73 | * PWM chip 74 | */ 75 | class Adafruit_PWMServoDriver { 76 | public: 77 | Adafruit_PWMServoDriver(); 78 | Adafruit_PWMServoDriver(const uint8_t addr); 79 | Adafruit_PWMServoDriver(const uint8_t addr, TwoWire &i2c); 80 | void begin(uint8_t prescale = 0); 81 | void reset(); 82 | void sleep(); 83 | void wakeup(); 84 | void setExtClk(uint8_t prescale); 85 | void setPWMFreq(float freq); 86 | void setOutputMode(bool totempole); 87 | uint8_t getPWM(uint8_t num); 88 | void setPWM(uint8_t num, uint16_t on, uint16_t off); 89 | void setPin(uint8_t num, uint16_t val, bool invert = false); 90 | uint8_t readPrescale(void); 91 | void writeMicroseconds(uint8_t num, uint16_t Microseconds); 92 | 93 | void setOscillatorFrequency(uint32_t freq); 94 | uint32_t getOscillatorFrequency(void); 95 | 96 | private: 97 | uint8_t _i2caddr; 98 | TwoWire *_i2c; 99 | 100 | uint32_t _oscillator_freq; 101 | uint8_t read8(uint8_t addr); 102 | void write8(uint8_t addr, uint8_t d); 103 | }; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/examples/oscillator/oscillator.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for our Adafruit 16-channel PWM & Servo driver 3 | to calibrate the frequency of the oscillator clock of the PCA9685. 4 | 5 | CAUTION: DO NOT CONNECT ANY VOLTAGE HIGHER THAN THE BOARD LIMITS. 6 | For 3.3V boards, like the ESP8266, remove any 5V input. The setup will 7 | feed the voltage back into the board to measure the frequency. 8 | KABOEM, SMOKE if you use too much VOLTAGE. 9 | 10 | Connect the PCA9685 with I2C (Ground, VCC, SCL, SCA) and apply 11 | voltage on V+. See above not higher than board limits. 12 | Connect the signal (yellow pin, PWM) of the PCA9685 to your board: 13 | Default is pin 3, last of first block. 14 | Default is pin 14 (of your ESP8266). 15 | 16 | Formula for prescale to get the targetted frequency (=update_rate) is: 17 | prescale = round ( osc_clock / 4096 * update_rate) - 1 18 | rewritten: osc_clock = (prescale + 1) * 4096 * update_rate 19 | We will measure the real update_rate to assert the real osc_clock. 20 | 21 | ***************************************************/ 22 | 23 | #include 24 | #include 25 | 26 | // called this way, it uses the default address 0x40 27 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire); 28 | // you can also call it with a different address you want 29 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); 30 | // you can also call it with a different address and I2C interface 31 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire); 32 | 33 | #if (defined(ESP8266) || defined(ESP32)) 34 | 35 | // Applied frequency in the test: can be changed to get the optimal 36 | // oscillator calibration for your targetted frequency. 37 | #define FREQUENCY 50 38 | 39 | // CAUTION: ONLY CONNECT server and ESP WITHOUT 5V ON V+ or green breakout supply pins. Use 3.3V on V+ 40 | #define PIN_SERVO_FEEDBACK 3 // Connect Yellow PWM pin, 3 = last on first block 41 | #define PIN_BOARD_FEEDBACK 14 // 14 => D5 on NodeMCU 42 | 43 | uint8_t prescale = 0; 44 | // loop 45 | #define INTERVAL 1000 // 1 sec 46 | int32_t lastEvaluation = 0; 47 | uint16_t frozenCounter = 0; 48 | uint16_t countDeviations = 0; 49 | 50 | uint32_t totalCounter = 0; 51 | uint32_t totalTime = 0; // in millis 52 | uint32_t realOsciFreq = 0; 53 | uint32_t multiplier = 4096; 54 | 55 | // interrupt 56 | volatile uint16_t interruptCounter = 0; 57 | 58 | ICACHE_RAM_ATTR void handleInterrupt() { 59 | interruptCounter++; 60 | } 61 | 62 | void setup() { 63 | Serial.begin(115200); 64 | Serial.println("PCA9685 Oscillator test"); 65 | 66 | // set PCA9685 67 | pwm.begin(); 68 | pwm.setPWMFreq(FREQUENCY); // Set some frequency 69 | pwm.setPWM(PIN_SERVO_FEEDBACK,0,2048); // half of time high, half of time low 70 | prescale = pwm.readPrescale(); // read prescale 71 | Serial.printf("Target frequency: %u\n", FREQUENCY); 72 | Serial.printf("Applied prescale: %u\n", prescale); 73 | 74 | // prepare interrupt on ESP pin 75 | pinMode(PIN_BOARD_FEEDBACK, INPUT); 76 | attachInterrupt(digitalPinToInterrupt(PIN_BOARD_FEEDBACK), handleInterrupt, RISING); 77 | 78 | // take a breath and reset to zero 79 | delay(10); 80 | interruptCounter = 0; 81 | lastEvaluation = millis(); 82 | } 83 | 84 | void loop() { 85 | if (millis() - lastEvaluation > INTERVAL) 86 | { 87 | // first freeze counters and adjust for new round 88 | frozenCounter = interruptCounter; // first freeze counter 89 | interruptCounter -= frozenCounter; 90 | lastEvaluation += INTERVAL; 91 | 92 | totalCounter += frozenCounter; 93 | totalTime += 1; 94 | 95 | // only print deviations from targetted frequency 96 | //if (frozenCounter != FREQUENCY) 97 | { 98 | multiplier = 4096; 99 | realOsciFreq = (prescale + 1) * totalCounter; // first part calcutlation 100 | // now follows an ugly hack to have maximum precision in 32 bits 101 | while (((realOsciFreq & 0x80000000) == 0) && (multiplier != 1)) 102 | { 103 | realOsciFreq <<= 1; 104 | multiplier >>= 1; 105 | } 106 | realOsciFreq /= totalTime; 107 | if (multiplier) realOsciFreq *= multiplier; 108 | 109 | countDeviations++; 110 | Serial.printf("%4u", countDeviations); 111 | Serial.printf(" Timestamp: %4u ", totalTime); 112 | Serial.printf(" Freq: %4u ", frozenCounter); 113 | Serial.printf(" Counter: %6u ", totalCounter); 114 | Serial.printf(" calc.osci.freq: %9u\n",realOsciFreq); 115 | } 116 | } 117 | 118 | } 119 | #else 120 | 121 | void setup() { 122 | Serial.begin(115200); 123 | Serial.println("PCA9685 Oscillator test"); 124 | Serial.println("yet not available for your board."); // please help adapt the code! 125 | } 126 | 127 | void loop() {} 128 | 129 | #endif // ESP8266/ESP32 130 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/examples/servo/servo.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for our Adafruit 16-channel PWM & Servo driver 3 | Servo test - this will drive 8 servos, one after the other on the 4 | first 8 pins of the PCA9685 5 | 6 | Pick one up today in the adafruit shop! 7 | ------> http://www.adafruit.com/products/815 8 | 9 | These drivers use I2C to communicate, 2 pins are required to 10 | interface. 11 | 12 | Adafruit invests time and resources providing this open source code, 13 | please support Adafruit and open-source hardware by purchasing 14 | products from Adafruit! 15 | 16 | Written by Limor Fried/Ladyada for Adafruit Industries. 17 | BSD license, all text above must be included in any redistribution 18 | ****************************************************/ 19 | 20 | #include 21 | #include 22 | 23 | // called this way, it uses the default address 0x40 24 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); 25 | // you can also call it with a different address you want 26 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41); 27 | // you can also call it with a different address and I2C interface 28 | //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire); 29 | 30 | // Depending on your servo make, the pulse width min and max may vary, you 31 | // want these to be as small/large as possible without hitting the hard stop 32 | // for max range. You'll have to tweak them as necessary to match the servos you 33 | // have! 34 | #define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096) 35 | #define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096) 36 | #define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150 37 | #define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600 38 | #define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates 39 | 40 | // our servo # counter 41 | uint8_t servonum = 0; 42 | 43 | void setup() { 44 | Serial.begin(9600); 45 | Serial.println("8 channel Servo test!"); 46 | 47 | pwm.begin(); 48 | /* 49 | * In theory the internal oscillator (clock) is 25MHz but it really isn't 50 | * that precise. You can 'calibrate' this by tweaking this number until 51 | * you get the PWM update frequency you're expecting! 52 | * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and 53 | * is used for calculating things like writeMicroseconds() 54 | * Analog servos run at ~50 Hz updates, It is importaint to use an 55 | * oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip. 56 | * 1) Attach the oscilloscope to one of the PWM signal pins and ground on 57 | * the I2C PCA9685 chip you are setting the value for. 58 | * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the 59 | * expected value (50Hz for most ESCs) 60 | * Setting the value here is specific to each individual I2C PCA9685 chip and 61 | * affects the calculations for the PWM update frequency. 62 | * Failure to correctly set the int.osc value will cause unexpected PWM results 63 | */ 64 | pwm.setOscillatorFrequency(27000000); 65 | pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates 66 | 67 | delay(10); 68 | } 69 | 70 | // You can use this function if you'd like to set the pulse length in seconds 71 | // e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise! 72 | void setServoPulse(uint8_t n, double pulse) { 73 | double pulselength; 74 | 75 | pulselength = 1000000; // 1,000,000 us per second 76 | pulselength /= SERVO_FREQ; // Analog servos run at ~60 Hz updates 77 | Serial.print(pulselength); Serial.println(" us per period"); 78 | pulselength /= 4096; // 12 bits of resolution 79 | Serial.print(pulselength); Serial.println(" us per bit"); 80 | pulse *= 1000000; // convert input seconds to us 81 | pulse /= pulselength; 82 | Serial.println(pulse); 83 | pwm.setPWM(n, 0, pulse); 84 | } 85 | 86 | void loop() { 87 | // Drive each servo one at a time using setPWM() 88 | Serial.println(servonum); 89 | for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) { 90 | pwm.setPWM(servonum, 0, pulselen); 91 | } 92 | 93 | delay(500); 94 | for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) { 95 | pwm.setPWM(servonum, 0, pulselen); 96 | } 97 | 98 | delay(500); 99 | 100 | // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding! 101 | // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 102 | for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) { 103 | pwm.writeMicroseconds(servonum, microsec); 104 | } 105 | 106 | delay(500); 107 | for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) { 108 | pwm.writeMicroseconds(servonum, microsec); 109 | } 110 | 111 | delay(500); 112 | 113 | servonum++; 114 | if (servonum > 7) servonum = 0; // Testing the first 8 servo channels 115 | } 116 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "TSL2561.h" 6 | #include "Adafruit_PWMServoDriver.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | TSL2561 tsl; 19 | Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x60); 20 | struct spi_ioc_transfer xfer[2]; 21 | 22 | int spi_init(char filename[40]){ 23 | int file; 24 | 25 | if ((file = open(filename,O_RDWR)) < 0) 26 | { 27 | printf("Failed to open the bus."); 28 | /* ERROR HANDLING; you can check errno to see what went wrong */ 29 | exit(1); 30 | } 31 | return file; 32 | } 33 | 34 | void write_PDM_Clock_Divider(int file, uint16_t div){ 35 | int status; 36 | char buf1[2] = {12,div}; 37 | char buf2[2] = {13,div>>8}; 38 | //xfer.tx_buf = (unsigned long) buf_out; 39 | //xfer.len = 4; /* Length of command to write*/ 40 | xfer[0].rx_buf = (unsigned long) NULL; 41 | xfer[0].tx_buf = (unsigned long) buf1; 42 | xfer[0].len = 2; /* Length of Data to read */ 43 | xfer[0].cs_change = 1; 44 | xfer[1].rx_buf = (unsigned long) NULL; 45 | xfer[1].tx_buf = (unsigned long) buf2; 46 | xfer[1].len = 2; /* Length of Data to read */ 47 | 48 | status = ioctl(file, SPI_IOC_MESSAGE(2), &xfer); 49 | if (status < 0) { 50 | perror("SPI_IOC_MESSAGE"); 51 | return ; 52 | } 53 | } 54 | 55 | void write_PDM_value(int file, uint16_t val){ 56 | int status; 57 | char buf1[2] = {10,val}; 58 | char buf2[2] = {11,val>>8}; 59 | 60 | //printf("sent: %02x %02x %02x %02x\n", buf1[0], buf1[1], buf2[0], buf2[1]); 61 | //xfer.tx_buf = (unsigned long) buf_out; 62 | //xfer.len = 4; /* Length of command to write*/ 63 | xfer[0].rx_buf = (unsigned long) NULL; 64 | xfer[0].tx_buf = (unsigned long) buf1; 65 | xfer[0].len = 2; /* Length of Data to read */ 66 | xfer[0].cs_change = 1; 67 | xfer[1].rx_buf = (unsigned long) NULL; 68 | xfer[1].tx_buf = (unsigned long) buf2; 69 | xfer[1].len = 2; /* Length of Data to read */ 70 | 71 | 72 | status = ioctl(file, SPI_IOC_MESSAGE(2), &xfer); 73 | if (status < 0) { 74 | perror("SPI_IOC_MESSAGE"); 75 | return ; 76 | } 77 | 78 | } 79 | 80 | 81 | void enable_PDM(int file){ 82 | int status; 83 | char buf[2] = {0x00,0x10}; 84 | //xfer.tx_buf = (unsigned long) buf_out; 85 | //xfer.len = 4; /* Length of command to write*/ 86 | xfer[0].rx_buf = (unsigned long) NULL; 87 | xfer[0].tx_buf = (unsigned long) buf; 88 | xfer[0].len = 2; /* Length of Data to read */ 89 | 90 | status = ioctl(file, SPI_IOC_MESSAGE(1), &xfer); 91 | if (status < 0) { 92 | perror("SPI_IOC_MESSAGE"); 93 | return ; 94 | } 95 | } 96 | 97 | int main(int argc, char **argv) 98 | { 99 | if (argc < 2){ 100 | cout << "./main [lowest_pwm]" << "\n"; 101 | } 102 | int input = atoi(argv[1]); 103 | if(input > 4095) input = 4095; 104 | if(input < 0) input = 0; 105 | uint16_t lowest_PWM = input; 106 | 107 | int fd = wiringPiI2CSetup(TSL2561_ADDR_LOW); 108 | cout << "Init result: "<< fd << endl; 109 | 110 | if (tsl.begin(fd)) { 111 | cout << "Found sensor"<< fd << endl; 112 | } else { 113 | cout << "No sensor"<< fd << endl; 114 | while (1); 115 | } 116 | 117 | tsl.setGain(TSL2561_GAIN_16X); 118 | tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); 119 | 120 | 121 | memset((void*)xfer,0,sizeof(xfer)); 122 | xfer[1].cs_change = 0; 123 | xfer[1].delay_usecs = 0; 124 | xfer[1].speed_hz = 6250000; 125 | xfer[1].bits_per_word = 8; 126 | xfer[0].cs_change = 0; 127 | xfer[0].delay_usecs = 0; 128 | xfer[0].speed_hz = 6250000; 129 | xfer[0].bits_per_word = 8; 130 | 131 | int file_conf=spi_init("/dev/spidev0.0"); 132 | enable_PDM(file_conf); 133 | write_PDM_Clock_Divider(file_conf,3000); 134 | 135 | pwm.begin(); 136 | pwm.setPWMFreq(1000); 137 | for(int i=12;i<16;i++) 138 | pwm.setPWM(i, 0, 0); 139 | for (uint8_t pwmnum=4; pwmnum < 12; pwmnum++) { 140 | pwm.setPWM(pwmnum, 0, 4095); 141 | } 142 | 143 | while(1) 144 | { 145 | uint32_t lum = tsl.getFullLuminosity(); 146 | uint16_t ir, full; 147 | ir = lum >> 16; 148 | full = lum & 0xFFFF; 149 | uint32_t lux = tsl.calculateLux(full, ir); 150 | 151 | 152 | uint16_t dutyCycle = pow(1.009, lux)*720.161525918474+2000; 153 | if (dutyCycle>65535){ 154 | dutyCycle = 65535; 155 | } 156 | cout << "Lux:" << lux < 42 | #include 43 | #define TSL2561_VISIBLE 2 // channel 0 - channel 1 44 | #define TSL2561_INFRARED 1 // channel 1 45 | #define TSL2561_FULLSPECTRUM 0 // channel 0 46 | 47 | // 3 i2c address options! 48 | #define TSL2561_ADDR_LOW 0x29 49 | #define TSL2561_ADDR_FLOAT 0x39 50 | #define TSL2561_ADDR_HIGH 0x49 51 | 52 | // Lux calculations differ slightly for CS package 53 | //#define TSL2561_PACKAGE_CS 54 | #define TSL2561_PACKAGE_T_FN_CL 55 | 56 | #define TSL2561_READBIT (0x01) 57 | 58 | #define TSL2561_COMMAND_BIT (0x80) // Must be 1 59 | #define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) 60 | #define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) 61 | #define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write 62 | 63 | #define TSL2561_CONTROL_POWERON (0x03) 64 | #define TSL2561_CONTROL_POWEROFF (0x00) 65 | 66 | #define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 67 | #define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 68 | #define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 69 | #define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE 70 | #define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE 71 | 72 | // T, FN and CL package values 73 | #define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE 74 | #define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE 75 | #define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE 76 | #define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE 77 | #define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE 78 | #define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE 79 | #define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE 80 | #define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE 81 | #define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE 82 | #define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE 83 | #define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE 84 | #define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE 85 | #define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE 86 | #define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE 87 | #define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE 88 | #define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE 89 | #define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE 90 | #define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE 91 | #define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE 92 | #define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE 93 | #define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE 94 | #define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE 95 | #define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE 96 | #define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE 97 | 98 | // CS package values 99 | #define TSL2561_LUX_K1C (0x0043) // 0.130 * 2^RATIO_SCALE 100 | #define TSL2561_LUX_B1C (0x0204) // 0.0315 * 2^LUX_SCALE 101 | #define TSL2561_LUX_M1C (0x01ad) // 0.0262 * 2^LUX_SCALE 102 | #define TSL2561_LUX_K2C (0x0085) // 0.260 * 2^RATIO_SCALE 103 | #define TSL2561_LUX_B2C (0x0228) // 0.0337 * 2^LUX_SCALE 104 | #define TSL2561_LUX_M2C (0x02c1) // 0.0430 * 2^LUX_SCALE 105 | #define TSL2561_LUX_K3C (0x00c8) // 0.390 * 2^RATIO_SCALE 106 | #define TSL2561_LUX_B3C (0x0253) // 0.0363 * 2^LUX_SCALE 107 | #define TSL2561_LUX_M3C (0x0363) // 0.0529 * 2^LUX_SCALE 108 | #define TSL2561_LUX_K4C (0x010a) // 0.520 * 2^RATIO_SCALE 109 | #define TSL2561_LUX_B4C (0x0282) // 0.0392 * 2^LUX_SCALE 110 | #define TSL2561_LUX_M4C (0x03df) // 0.0605 * 2^LUX_SCALE 111 | #define TSL2561_LUX_K5C (0x014d) // 0.65 * 2^RATIO_SCALE 112 | #define TSL2561_LUX_B5C (0x0177) // 0.0229 * 2^LUX_SCALE 113 | #define TSL2561_LUX_M5C (0x01dd) // 0.0291 * 2^LUX_SCALE 114 | #define TSL2561_LUX_K6C (0x019a) // 0.80 * 2^RATIO_SCALE 115 | #define TSL2561_LUX_B6C (0x0101) // 0.0157 * 2^LUX_SCALE 116 | #define TSL2561_LUX_M6C (0x0127) // 0.0180 * 2^LUX_SCALE 117 | #define TSL2561_LUX_K7C (0x029a) // 1.3 * 2^RATIO_SCALE 118 | #define TSL2561_LUX_B7C (0x0037) // 0.00338 * 2^LUX_SCALE 119 | #define TSL2561_LUX_M7C (0x002b) // 0.00260 * 2^LUX_SCALE 120 | #define TSL2561_LUX_K8C (0x029a) // 1.3 * 2^RATIO_SCALE 121 | #define TSL2561_LUX_B8C (0x0000) // 0.000 * 2^LUX_SCALE 122 | #define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE 123 | 124 | enum 125 | { 126 | TSL2561_REGISTER_CONTROL = 0x00, 127 | TSL2561_REGISTER_TIMING = 0x01, 128 | TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, 129 | TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, 130 | TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, 131 | TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, 132 | TSL2561_REGISTER_INTERRUPT = 0x06, 133 | TSL2561_REGISTER_CRC = 0x08, 134 | TSL2561_REGISTER_ID = 0x0A, 135 | TSL2561_REGISTER_CHAN0_LOW = 0x0C, 136 | TSL2561_REGISTER_CHAN0_HIGH = 0x0D, 137 | TSL2561_REGISTER_CHAN1_LOW = 0x0E, 138 | TSL2561_REGISTER_CHAN1_HIGH = 0x0F 139 | }; 140 | 141 | typedef enum 142 | { 143 | TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms 144 | TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms 145 | TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms 146 | } 147 | tsl2561IntegrationTime_t; 148 | 149 | typedef enum 150 | { 151 | TSL2561_GAIN_0X = 0x00, // No gain 152 | TSL2561_GAIN_16X = 0x10, // 16x gain 153 | } 154 | tsl2561Gain_t; 155 | 156 | 157 | class TSL2561 { 158 | public: 159 | TSL2561(); 160 | bool begin(int fd); 161 | void enable(void); 162 | void disable(void); 163 | void write8(uint8_t r, uint8_t v); 164 | uint16_t read16(uint8_t reg); 165 | 166 | uint32_t calculateLux(uint16_t ch0, uint16_t ch1); 167 | void setTiming(tsl2561IntegrationTime_t integration); 168 | void setGain(tsl2561Gain_t gain); 169 | uint16_t getLuminosity (uint8_t channel); 170 | uint32_t getFullLuminosity (); 171 | 172 | private: 173 | int8_t _addr; 174 | tsl2561IntegrationTime_t _integration; 175 | tsl2561Gain_t _gain; 176 | int _fd; 177 | 178 | bool _initialized; 179 | }; 180 | #endif 181 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/TSL2561.h: -------------------------------------------------------------------------------- 1 | 2 | /**************************************************************************/ 3 | /*! 4 | @file tsl2561.h 5 | @author K. Townsend (microBuilder.eu) 6 | 7 | @section LICENSE 8 | 9 | Software License Agreement (BSD License) 10 | 11 | Copyright (c) 2010, microBuilder SARL 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | 1. Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | 2. Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 3. Neither the name of the copyright holders nor the 22 | names of its contributors may be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 26 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 29 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | /**************************************************************************/ 37 | 38 | #ifndef _TSL2561_H_ 39 | #define _TSL2561_H_ 40 | 41 | #if ARDUINO >= 100 42 | #include 43 | #else 44 | #include 45 | #endif 46 | #include 47 | 48 | #define TSL2561_VISIBLE 2 // channel 0 - channel 1 49 | #define TSL2561_INFRARED 1 // channel 1 50 | #define TSL2561_FULLSPECTRUM 0 // channel 0 51 | 52 | // 3 i2c address options! 53 | #define TSL2561_ADDR_LOW 0x29 54 | #define TSL2561_ADDR_FLOAT 0x39 55 | #define TSL2561_ADDR_HIGH 0x49 56 | 57 | // Lux calculations differ slightly for CS package 58 | //#define TSL2561_PACKAGE_CS 59 | #define TSL2561_PACKAGE_T_FN_CL 60 | 61 | #define TSL2561_READBIT (0x01) 62 | 63 | #define TSL2561_COMMAND_BIT (0x80) // Must be 1 64 | #define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) 65 | #define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) 66 | #define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write 67 | 68 | #define TSL2561_CONTROL_POWERON (0x03) 69 | #define TSL2561_CONTROL_POWEROFF (0x00) 70 | 71 | #define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 72 | #define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 73 | #define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 74 | #define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE 75 | #define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE 76 | 77 | // T, FN and CL package values 78 | #define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE 79 | #define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE 80 | #define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE 81 | #define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE 82 | #define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE 83 | #define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE 84 | #define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE 85 | #define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE 86 | #define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE 87 | #define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE 88 | #define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE 89 | #define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE 90 | #define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE 91 | #define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE 92 | #define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE 93 | #define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE 94 | #define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE 95 | #define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE 96 | #define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE 97 | #define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE 98 | #define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE 99 | #define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE 100 | #define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE 101 | #define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE 102 | 103 | // CS package values 104 | #define TSL2561_LUX_K1C (0x0043) // 0.130 * 2^RATIO_SCALE 105 | #define TSL2561_LUX_B1C (0x0204) // 0.0315 * 2^LUX_SCALE 106 | #define TSL2561_LUX_M1C (0x01ad) // 0.0262 * 2^LUX_SCALE 107 | #define TSL2561_LUX_K2C (0x0085) // 0.260 * 2^RATIO_SCALE 108 | #define TSL2561_LUX_B2C (0x0228) // 0.0337 * 2^LUX_SCALE 109 | #define TSL2561_LUX_M2C (0x02c1) // 0.0430 * 2^LUX_SCALE 110 | #define TSL2561_LUX_K3C (0x00c8) // 0.390 * 2^RATIO_SCALE 111 | #define TSL2561_LUX_B3C (0x0253) // 0.0363 * 2^LUX_SCALE 112 | #define TSL2561_LUX_M3C (0x0363) // 0.0529 * 2^LUX_SCALE 113 | #define TSL2561_LUX_K4C (0x010a) // 0.520 * 2^RATIO_SCALE 114 | #define TSL2561_LUX_B4C (0x0282) // 0.0392 * 2^LUX_SCALE 115 | #define TSL2561_LUX_M4C (0x03df) // 0.0605 * 2^LUX_SCALE 116 | #define TSL2561_LUX_K5C (0x014d) // 0.65 * 2^RATIO_SCALE 117 | #define TSL2561_LUX_B5C (0x0177) // 0.0229 * 2^LUX_SCALE 118 | #define TSL2561_LUX_M5C (0x01dd) // 0.0291 * 2^LUX_SCALE 119 | #define TSL2561_LUX_K6C (0x019a) // 0.80 * 2^RATIO_SCALE 120 | #define TSL2561_LUX_B6C (0x0101) // 0.0157 * 2^LUX_SCALE 121 | #define TSL2561_LUX_M6C (0x0127) // 0.0180 * 2^LUX_SCALE 122 | #define TSL2561_LUX_K7C (0x029a) // 1.3 * 2^RATIO_SCALE 123 | #define TSL2561_LUX_B7C (0x0037) // 0.00338 * 2^LUX_SCALE 124 | #define TSL2561_LUX_M7C (0x002b) // 0.00260 * 2^LUX_SCALE 125 | #define TSL2561_LUX_K8C (0x029a) // 1.3 * 2^RATIO_SCALE 126 | #define TSL2561_LUX_B8C (0x0000) // 0.000 * 2^LUX_SCALE 127 | #define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE 128 | 129 | enum 130 | { 131 | TSL2561_REGISTER_CONTROL = 0x00, 132 | TSL2561_REGISTER_TIMING = 0x01, 133 | TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, 134 | TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, 135 | TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, 136 | TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, 137 | TSL2561_REGISTER_INTERRUPT = 0x06, 138 | TSL2561_REGISTER_CRC = 0x08, 139 | TSL2561_REGISTER_ID = 0x0A, 140 | TSL2561_REGISTER_CHAN0_LOW = 0x0C, 141 | TSL2561_REGISTER_CHAN0_HIGH = 0x0D, 142 | TSL2561_REGISTER_CHAN1_LOW = 0x0E, 143 | TSL2561_REGISTER_CHAN1_HIGH = 0x0F 144 | }; 145 | 146 | typedef enum 147 | { 148 | TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms 149 | TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms 150 | TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms 151 | } 152 | tsl2561IntegrationTime_t; 153 | 154 | typedef enum 155 | { 156 | TSL2561_GAIN_0X = 0x00, // No gain 157 | TSL2561_GAIN_16X = 0x10, // 16x gain 158 | } 159 | tsl2561Gain_t; 160 | 161 | 162 | class TSL2561 { 163 | public: 164 | TSL2561(uint8_t addr); 165 | boolean begin(void); 166 | void enable(void); 167 | void disable(void); 168 | void write8(uint8_t r, uint8_t v); 169 | uint16_t read16(uint8_t reg); 170 | 171 | uint32_t calculateLux(uint16_t ch0, uint16_t ch1); 172 | void setTiming(tsl2561IntegrationTime_t integration); 173 | void setGain(tsl2561Gain_t gain); 174 | uint16_t getLuminosity (uint8_t channel); 175 | uint32_t getFullLuminosity (); 176 | 177 | private: 178 | int8_t _addr; 179 | tsl2561IntegrationTime_t _integration; 180 | tsl2561Gain_t _gain; 181 | 182 | boolean _initialized; 183 | }; 184 | #endif 185 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file tsl2561.c 4 | @author K. Townsend (microBuilder.eu / adafruit.com) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2010, microBuilder SARL, Adafruit Industries 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | #include 38 | #include 39 | #include "TSL2561.h" 40 | #include 41 | #include 42 | #include 43 | using namespace std; 44 | 45 | TSL2561::TSL2561() { 46 | _initialized = false; 47 | _integration = TSL2561_INTEGRATIONTIME_13MS; 48 | _gain = TSL2561_GAIN_16X; 49 | // we cant do wire initialization till later, because we havent loaded Wire yet 50 | } 51 | 52 | bool TSL2561::begin(int fd) { 53 | _fd = fd; 54 | _fd = wiringPiI2CSetup(TSL2561_ADDR_LOW); 55 | uint8_t x = wiringPiI2CReadReg8(fd,TSL2561_REGISTER_ID); 56 | //Serial.print("0x"); Serial.println(x, HEX); 57 | if (x & 0x0A ) { 58 | cout << "Found TSL2561" << endl; 59 | } else { 60 | cout << "TSL2561 Not Found" << endl; 61 | while(1){ 62 | } 63 | } 64 | 65 | _initialized = true; 66 | 67 | // Set default integration time and gain 68 | setTiming(_integration); 69 | setGain(_gain); 70 | // Note: by default, the device is in power down mode on bootup 71 | disable(); 72 | 73 | return true; 74 | } 75 | 76 | void TSL2561::enable(void) 77 | { 78 | if (!_initialized) begin(_fd); 79 | 80 | // Enable the device by setting the control bit to 0x03 81 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); 82 | } 83 | 84 | void TSL2561::disable(void) 85 | { 86 | if (!_initialized) begin(_fd); 87 | 88 | // Disable the device by setting the control bit to 0x03 89 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); 90 | } 91 | 92 | 93 | void TSL2561::setGain(tsl2561Gain_t gain) { 94 | if (!_initialized) begin(_fd); 95 | 96 | enable(); 97 | _gain = gain; 98 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); 99 | disable(); 100 | } 101 | 102 | void TSL2561::setTiming(tsl2561IntegrationTime_t integration) 103 | { 104 | if (!_initialized) begin(_fd); 105 | 106 | enable(); 107 | _integration = integration; 108 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); 109 | disable(); 110 | } 111 | 112 | uint32_t TSL2561::calculateLux(uint16_t ch0, uint16_t ch1) 113 | { 114 | unsigned long chScale; 115 | unsigned long channel1; 116 | unsigned long channel0; 117 | 118 | switch (_integration) 119 | { 120 | case TSL2561_INTEGRATIONTIME_13MS: 121 | chScale = TSL2561_LUX_CHSCALE_TINT0; 122 | break; 123 | case TSL2561_INTEGRATIONTIME_101MS: 124 | chScale = TSL2561_LUX_CHSCALE_TINT1; 125 | break; 126 | default: // No scaling ... integration time = 402ms 127 | chScale = (1 << TSL2561_LUX_CHSCALE); 128 | break; 129 | } 130 | 131 | // Scale for gain (1x or 16x) 132 | if (!_gain) chScale = chScale << 4; 133 | 134 | // scale the channel values 135 | channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE; 136 | channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE; 137 | 138 | // find the ratio of the channel values (Channel1/Channel0) 139 | unsigned long ratio1 = 0; 140 | if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; 141 | 142 | // round the ratio value 143 | unsigned long ratio = (ratio1 + 1) >> 1; 144 | 145 | unsigned int b, m; 146 | 147 | #ifdef TSL2561_PACKAGE_CS 148 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) 149 | {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;} 150 | else if (ratio <= TSL2561_LUX_K2C) 151 | {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;} 152 | else if (ratio <= TSL2561_LUX_K3C) 153 | {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;} 154 | else if (ratio <= TSL2561_LUX_K4C) 155 | {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;} 156 | else if (ratio <= TSL2561_LUX_K5C) 157 | {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;} 158 | else if (ratio <= TSL2561_LUX_K6C) 159 | {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;} 160 | else if (ratio <= TSL2561_LUX_K7C) 161 | {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;} 162 | else if (ratio > TSL2561_LUX_K8C) 163 | {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;} 164 | #else 165 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) 166 | {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} 167 | else if (ratio <= TSL2561_LUX_K2T) 168 | {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} 169 | else if (ratio <= TSL2561_LUX_K3T) 170 | {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} 171 | else if (ratio <= TSL2561_LUX_K4T) 172 | {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} 173 | else if (ratio <= TSL2561_LUX_K5T) 174 | {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} 175 | else if (ratio <= TSL2561_LUX_K6T) 176 | {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} 177 | else if (ratio <= TSL2561_LUX_K7T) 178 | {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} 179 | else if (ratio > TSL2561_LUX_K8T) 180 | {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} 181 | #endif 182 | 183 | unsigned long temp; 184 | temp = ((channel0 * b) - (channel1 * m)); 185 | 186 | // do not allow negative lux value 187 | if (temp < 0) temp = 0; 188 | 189 | // round lsb (2^(LUX_SCALE-1)) 190 | temp += (1 << (TSL2561_LUX_LUXSCALE-1)); 191 | 192 | // strip off fractional portion 193 | uint32_t lux = temp >> TSL2561_LUX_LUXSCALE; 194 | 195 | // Signal I2C had no errors 196 | return lux; 197 | } 198 | 199 | uint32_t TSL2561::getFullLuminosity (void) 200 | { 201 | if (!_initialized) begin(_fd); 202 | 203 | // Enable the device by setting the control bit to 0x03 204 | enable(); 205 | 206 | // Wait x ms for ADC to complete 207 | switch (_integration) 208 | { 209 | case TSL2561_INTEGRATIONTIME_13MS: 210 | usleep(14000); 211 | break; 212 | case TSL2561_INTEGRATIONTIME_101MS: 213 | usleep(102000); 214 | break; 215 | default: 216 | usleep(403000); 217 | break; 218 | } 219 | 220 | uint32_t x; 221 | x = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); 222 | x <<= 16; 223 | x |= read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); 224 | 225 | disable(); 226 | 227 | return x; 228 | } 229 | uint16_t TSL2561::getLuminosity (uint8_t channel) { 230 | 231 | uint32_t x = getFullLuminosity(); 232 | 233 | if (channel == 0) { 234 | // Reads two byte value from channel 0 (visible + infrared) 235 | return (x & 0xFFFF); 236 | } else if (channel == 1) { 237 | // Reads two byte value from channel 1 (infrared) 238 | return (x >> 16); 239 | } else if (channel == 2) { 240 | // Reads all and subtracts out just the visible! 241 | return ( (x & 0xFFFF) - (x >> 16)); 242 | } 243 | 244 | // unknown channel! 245 | return 0; 246 | } 247 | 248 | 249 | uint16_t TSL2561::read16(uint8_t reg) 250 | { 251 | return wiringPiI2CReadReg16(_fd,reg); 252 | } 253 | 254 | 255 | 256 | void TSL2561::write8 (uint8_t reg, uint8_t value) 257 | { 258 | wiringPiI2CWriteReg8(_fd,reg,value); 259 | } 260 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/TSL2561/TSL2561.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file tsl2561.c 4 | @author K. Townsend (microBuilder.eu / adafruit.com) 5 | 6 | @section LICENSE 7 | 8 | Software License Agreement (BSD License) 9 | 10 | Copyright (c) 2010, microBuilder SARL, Adafruit Industries 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 1. Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 3. Neither the name of the copyright holders nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 25 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 28 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | /**************************************************************************/ 36 | 37 | #if defined ( ESP8266 ) 38 | #include 39 | #else 40 | #include 41 | #include 42 | #endif 43 | #include 44 | 45 | #include "TSL2561.h" 46 | 47 | TSL2561::TSL2561(uint8_t addr) { 48 | _addr = addr; 49 | _initialized = false; 50 | _integration = TSL2561_INTEGRATIONTIME_13MS; 51 | _gain = TSL2561_GAIN_16X; 52 | 53 | // we cant do wire initialization till later, because we havent loaded Wire yet 54 | } 55 | 56 | boolean TSL2561::begin(void) { 57 | Wire.begin(); 58 | 59 | // Initialise I2C 60 | Wire.beginTransmission(_addr); 61 | #if ARDUINO >= 100 62 | Wire.write(TSL2561_REGISTER_ID); 63 | #else 64 | Wire.send(TSL2561_REGISTER_ID); 65 | #endif 66 | Wire.endTransmission(); 67 | Wire.requestFrom(_addr, 1); 68 | #if ARDUINO >= 100 69 | int x = Wire.read(); 70 | #else 71 | int x = Wire.receive(); 72 | #endif 73 | //Serial.print("0x"); Serial.println(x, HEX); 74 | if (x & 0x0A ) { 75 | //Serial.println("Found TSL2561"); 76 | } else { 77 | return false; 78 | } 79 | _initialized = true; 80 | 81 | // Set default integration time and gain 82 | setTiming(_integration); 83 | setGain(_gain); 84 | // Note: by default, the device is in power down mode on bootup 85 | disable(); 86 | 87 | return true; 88 | } 89 | 90 | void TSL2561::enable(void) 91 | { 92 | if (!_initialized) begin(); 93 | 94 | // Enable the device by setting the control bit to 0x03 95 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); 96 | } 97 | 98 | void TSL2561::disable(void) 99 | { 100 | if (!_initialized) begin(); 101 | 102 | // Disable the device by setting the control bit to 0x03 103 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); 104 | } 105 | 106 | 107 | void TSL2561::setGain(tsl2561Gain_t gain) { 108 | if (!_initialized) begin(); 109 | 110 | enable(); 111 | _gain = gain; 112 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); 113 | disable(); 114 | } 115 | 116 | void TSL2561::setTiming(tsl2561IntegrationTime_t integration) 117 | { 118 | if (!_initialized) begin(); 119 | 120 | enable(); 121 | _integration = integration; 122 | write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain); 123 | disable(); 124 | } 125 | 126 | uint32_t TSL2561::calculateLux(uint16_t ch0, uint16_t ch1) 127 | { 128 | unsigned long chScale; 129 | unsigned long channel1; 130 | unsigned long channel0; 131 | 132 | switch (_integration) 133 | { 134 | case TSL2561_INTEGRATIONTIME_13MS: 135 | chScale = TSL2561_LUX_CHSCALE_TINT0; 136 | break; 137 | case TSL2561_INTEGRATIONTIME_101MS: 138 | chScale = TSL2561_LUX_CHSCALE_TINT1; 139 | break; 140 | default: // No scaling ... integration time = 402ms 141 | chScale = (1 << TSL2561_LUX_CHSCALE); 142 | break; 143 | } 144 | 145 | // Scale for gain (1x or 16x) 146 | if (!_gain) chScale = chScale << 4; 147 | 148 | // scale the channel values 149 | channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE; 150 | channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE; 151 | 152 | // find the ratio of the channel values (Channel1/Channel0) 153 | unsigned long ratio1 = 0; 154 | if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; 155 | 156 | // round the ratio value 157 | unsigned long ratio = (ratio1 + 1) >> 1; 158 | 159 | unsigned int b, m; 160 | 161 | #ifdef TSL2561_PACKAGE_CS 162 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) 163 | {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;} 164 | else if (ratio <= TSL2561_LUX_K2C) 165 | {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;} 166 | else if (ratio <= TSL2561_LUX_K3C) 167 | {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;} 168 | else if (ratio <= TSL2561_LUX_K4C) 169 | {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;} 170 | else if (ratio <= TSL2561_LUX_K5C) 171 | {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;} 172 | else if (ratio <= TSL2561_LUX_K6C) 173 | {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;} 174 | else if (ratio <= TSL2561_LUX_K7C) 175 | {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;} 176 | else if (ratio > TSL2561_LUX_K8C) 177 | {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;} 178 | #else 179 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) 180 | {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} 181 | else if (ratio <= TSL2561_LUX_K2T) 182 | {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} 183 | else if (ratio <= TSL2561_LUX_K3T) 184 | {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} 185 | else if (ratio <= TSL2561_LUX_K4T) 186 | {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} 187 | else if (ratio <= TSL2561_LUX_K5T) 188 | {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} 189 | else if (ratio <= TSL2561_LUX_K6T) 190 | {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} 191 | else if (ratio <= TSL2561_LUX_K7T) 192 | {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} 193 | else if (ratio > TSL2561_LUX_K8T) 194 | {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} 195 | #endif 196 | 197 | unsigned long temp; 198 | temp = ((channel0 * b) - (channel1 * m)); 199 | 200 | // do not allow negative lux value 201 | if (temp < 0) temp = 0; 202 | 203 | // round lsb (2^(LUX_SCALE-1)) 204 | temp += (1 << (TSL2561_LUX_LUXSCALE-1)); 205 | 206 | // strip off fractional portion 207 | uint32_t lux = temp >> TSL2561_LUX_LUXSCALE; 208 | 209 | // Signal I2C had no errors 210 | return lux; 211 | } 212 | 213 | uint32_t TSL2561::getFullLuminosity (void) 214 | { 215 | if (!_initialized) begin(); 216 | 217 | // Enable the device by setting the control bit to 0x03 218 | enable(); 219 | 220 | // Wait x ms for ADC to complete 221 | switch (_integration) 222 | { 223 | case TSL2561_INTEGRATIONTIME_13MS: 224 | delay(14); 225 | break; 226 | case TSL2561_INTEGRATIONTIME_101MS: 227 | delay(102); 228 | break; 229 | default: 230 | delay(403); 231 | break; 232 | } 233 | 234 | uint32_t x; 235 | x = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); 236 | x <<= 16; 237 | x |= read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); 238 | 239 | disable(); 240 | 241 | return x; 242 | } 243 | uint16_t TSL2561::getLuminosity (uint8_t channel) { 244 | 245 | uint32_t x = getFullLuminosity(); 246 | 247 | if (channel == 0) { 248 | // Reads two byte value from channel 0 (visible + infrared) 249 | return (x & 0xFFFF); 250 | } else if (channel == 1) { 251 | // Reads two byte value from channel 1 (infrared) 252 | return (x >> 16); 253 | } else if (channel == 2) { 254 | // Reads all and subtracts out just the visible! 255 | return ( (x & 0xFFFF) - (x >> 16)); 256 | } 257 | 258 | // unknown channel! 259 | return 0; 260 | } 261 | 262 | 263 | uint16_t TSL2561::read16(uint8_t reg) 264 | { 265 | uint16_t x; uint16_t t; 266 | 267 | Wire.beginTransmission(_addr); 268 | #if ARDUINO >= 100 269 | Wire.write(reg); 270 | #else 271 | Wire.send(reg); 272 | #endif 273 | Wire.endTransmission(); 274 | 275 | Wire.requestFrom(_addr, 2); 276 | #if ARDUINO >= 100 277 | t = Wire.read(); 278 | x = Wire.read(); 279 | #else 280 | t = Wire.receive(); 281 | x = Wire.receive(); 282 | #endif 283 | x <<= 8; 284 | x |= t; 285 | return x; 286 | } 287 | 288 | 289 | 290 | void TSL2561::write8 (uint8_t reg, uint8_t value) 291 | { 292 | Wire.beginTransmission(_addr); 293 | #if ARDUINO >= 100 294 | Wire.write(reg); 295 | Wire.write(value); 296 | #else 297 | Wire.send(reg); 298 | Wire.send(value); 299 | #endif 300 | Wire.endTransmission(); 301 | } 302 | -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit_PWMServoDriver.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_PWMServoDriver.cpp 3 | * 4 | * @mainpage Adafruit 16-channel PWM & Servo driver 5 | * 6 | * @section intro_sec Introduction 7 | * 8 | * This is a library for the 16-channel PWM & Servo driver. 9 | * 10 | * Designed specifically to work with the Adafruit PWM & Servo driver. 11 | * 12 | * Pick one up today in the adafruit shop! 13 | * ------> https://www.adafruit.com/product/815 14 | * 15 | * These displays use I2C to communicate, 2 pins are required to interface. 16 | * 17 | * Adafruit invests time and resources providing this open source code, 18 | * please support Adafruit andopen-source hardware by purchasing products 19 | * from Adafruit! 20 | * 21 | * @section author Author 22 | * 23 | * Limor Fried/Ladyada (Adafruit Industries). 24 | * 25 | * @section license License 26 | * 27 | * BSD license, all text above must be included in any redistribution 28 | */ 29 | 30 | #include "Adafruit_PWMServoDriver.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | using namespace std; 37 | 38 | //#define ENABLE_DEBUG_OUTPUT 39 | 40 | 41 | 42 | /*! 43 | * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a 44 | * TwoWire interface 45 | * @param addr The 7-bit I2C address to locate this chip, default is 0x40 46 | * @param i2c A reference to a 'TwoWire' object that we'll use to communicate 47 | * with 48 | */ 49 | Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr) 50 | : _i2caddr(addr) {} 51 | 52 | /*! 53 | * @brief Setups the I2C interface and hardware 54 | * @param prescale 55 | * Sets External Clock (Optional) 56 | */ 57 | void Adafruit_PWMServoDriver::begin(uint8_t prescale) { 58 | _fd = wiringPiI2CSetup(_i2caddr); 59 | cout << "PWM Init result: "<< _fd << endl; 60 | reset(); 61 | if (prescale) { 62 | setExtClk(prescale); 63 | } else { 64 | // set a default frequency 65 | setPWMFreq(1000); 66 | } 67 | // set the default internal frequency 68 | setOscillatorFrequency(FREQUENCY_OSCILLATOR); 69 | } 70 | 71 | /*! 72 | * @brief Sends a reset command to the PCA9685 chip over I2C 73 | */ 74 | void Adafruit_PWMServoDriver::reset() { 75 | write8(PCA9685_MODE1, MODE1_RESTART); 76 | usleep(10000); 77 | } 78 | 79 | /*! 80 | * @brief Puts board into sleep mode 81 | */ 82 | void Adafruit_PWMServoDriver::sleep() { 83 | uint8_t awake = read8(PCA9685_MODE1); 84 | uint8_t sleep = awake | MODE1_SLEEP; // set sleep bit high 85 | write8(PCA9685_MODE1, sleep); 86 | usleep(5000); // wait until cycle ends for sleep to be active 87 | } 88 | 89 | /*! 90 | * @brief Wakes board from sleep 91 | */ 92 | void Adafruit_PWMServoDriver::wakeup() { 93 | uint8_t sleep = read8(PCA9685_MODE1); 94 | uint8_t wakeup = sleep & ~MODE1_SLEEP; // set sleep bit low 95 | write8(PCA9685_MODE1, wakeup); 96 | } 97 | 98 | /*! 99 | * @brief Sets EXTCLK pin to use the external clock 100 | * @param prescale 101 | * Configures the prescale value to be used by the external clock 102 | */ 103 | void Adafruit_PWMServoDriver::setExtClk(uint8_t prescale) { 104 | uint8_t oldmode = read8(PCA9685_MODE1); 105 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 106 | write8(PCA9685_MODE1, newmode); // go to sleep, turn off internal oscillator 107 | 108 | // This sets both the SLEEP and EXTCLK bits of the MODE1 register to switch to 109 | // use the external clock. 110 | write8(PCA9685_MODE1, (newmode |= MODE1_EXTCLK)); 111 | 112 | write8(PCA9685_PRESCALE, prescale); // set the prescaler 113 | 114 | usleep(5000); 115 | // clear the SLEEP bit to start 116 | write8(PCA9685_MODE1, (newmode & ~MODE1_SLEEP) | MODE1_RESTART | MODE1_AI); 117 | 118 | } 119 | 120 | /*! 121 | * @brief Sets the PWM frequency for the entire chip, up to ~1.6 KHz 122 | * @param freq Floating point frequency that we will attempt to match 123 | */ 124 | void Adafruit_PWMServoDriver::setPWMFreq(float freq) { 125 | // Range output modulation frequency is dependant on oscillator 126 | if (freq < 1) 127 | freq = 1; 128 | if (freq > 3500) 129 | freq = 3500; // Datasheet limit is 3052=50MHz/(4*4096) 130 | 131 | float prescaleval = ((_oscillator_freq / (freq * 4096.0)) + 0.5) - 1; 132 | if (prescaleval < PCA9685_PRESCALE_MIN) 133 | prescaleval = PCA9685_PRESCALE_MIN; 134 | if (prescaleval > PCA9685_PRESCALE_MAX) 135 | prescaleval = PCA9685_PRESCALE_MAX; 136 | uint8_t prescale = (uint8_t)prescaleval; 137 | 138 | 139 | uint8_t oldmode = read8(PCA9685_MODE1); 140 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 141 | write8(PCA9685_MODE1, newmode); // go to sleep 142 | write8(PCA9685_PRESCALE, prescale); // set the prescaler 143 | write8(PCA9685_MODE1, oldmode); 144 | usleep(5000); 145 | // This sets the MODE1 register to turn on auto increment. 146 | write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI); 147 | 148 | } 149 | 150 | /*! 151 | * @brief Sets the output mode of the PCA9685 to either 152 | * open drain or push pull / totempole. 153 | * Warning: LEDs with integrated zener diodes should 154 | * only be driven in open drain mode. 155 | * @param totempole Totempole if true, open drain if false. 156 | */ 157 | void Adafruit_PWMServoDriver::setOutputMode(bool totempole) { 158 | uint8_t oldmode = read8(PCA9685_MODE2); 159 | uint8_t newmode; 160 | if (totempole) { 161 | newmode = oldmode | MODE2_OUTDRV; 162 | } else { 163 | newmode = oldmode & ~MODE2_OUTDRV; 164 | } 165 | write8(PCA9685_MODE2, newmode); 166 | 167 | } 168 | 169 | /*! 170 | * @brief Reads set Prescale from PCA9685 171 | * @return prescale value 172 | */ 173 | uint8_t Adafruit_PWMServoDriver::readPrescale(void) { 174 | return read8(PCA9685_PRESCALE); 175 | } 176 | 177 | /*! 178 | * @brief Gets the PWM output of one of the PCA9685 pins 179 | * @param num One of the PWM output pins, from 0 to 15 180 | * @return requested PWM output value 181 | */ 182 | uint8_t Adafruit_PWMServoDriver::getPWM(uint8_t num) { 183 | //_i2c->requestFrom((int)_i2caddr, PCA9685_LED0_ON_L + 4 * num, (int)4); 184 | 185 | return 0;//_i2c->read(); 186 | } 187 | 188 | /*! 189 | * @brief Sets the PWM output of one of the PCA9685 pins 190 | * @param num One of the PWM output pins, from 0 to 15 191 | * @param on At what point in the 4096-part cycle to turn the PWM output ON 192 | * @param off At what point in the 4096-part cycle to turn the PWM output OFF 193 | */ 194 | void Adafruit_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) { 195 | 196 | /* 197 | _i2c->beginTransmission(_i2caddr); 198 | _i2c->write(PCA9685_LED0_ON_L + 4 * num); 199 | _i2c->write(on); 200 | _i2c->write(on >> 8); 201 | _i2c->write(off); 202 | _i2c->write(off >> 8); 203 | _i2c->endTransmission(); 204 | */ 205 | wiringPiI2CWriteReg16(_fd,PCA9685_LED0_ON_L + 4 * num,on); 206 | wiringPiI2CWriteReg16(_fd,PCA9685_LED0_ON_L + 4 * num + 2,off); 207 | } 208 | 209 | /*! 210 | * @brief Helper to set pin PWM output. Sets pin without having to deal with 211 | * on/off tick placement and properly handles a zero value as completely off and 212 | * 4095 as completely on. Optional invert parameter supports inverting the 213 | * pulse for sinking to ground. 214 | * @param num One of the PWM output pins, from 0 to 15 215 | * @param val The number of ticks out of 4096 to be active, should be a value 216 | * from 0 to 4095 inclusive. 217 | * @param invert If true, inverts the output, defaults to 'false' 218 | */ 219 | void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) { 220 | // Clamp value between 0 and 4095 inclusive. 221 | val = min(val, (uint16_t)4095); 222 | if (invert) { 223 | if (val == 0) { 224 | // Special value for signal fully on. 225 | setPWM(num, 4096, 0); 226 | } else if (val == 4095) { 227 | // Special value for signal fully off. 228 | setPWM(num, 0, 4096); 229 | } else { 230 | setPWM(num, 0, 4095 - val); 231 | } 232 | } else { 233 | if (val == 4095) { 234 | // Special value for signal fully on. 235 | setPWM(num, 4096, 0); 236 | } else if (val == 0) { 237 | // Special value for signal fully off. 238 | setPWM(num, 0, 4096); 239 | } else { 240 | setPWM(num, 0, val); 241 | } 242 | } 243 | } 244 | 245 | /*! 246 | * @brief Sets the PWM output of one of the PCA9685 pins based on the input 247 | * microseconds, output is not precise 248 | * @param num One of the PWM output pins, from 0 to 15 249 | * @param Microseconds The number of Microseconds to turn the PWM output ON 250 | */ 251 | void Adafruit_PWMServoDriver::writeMicroseconds(uint8_t num, 252 | uint16_t Microseconds) { 253 | 254 | 255 | double pulse = Microseconds; 256 | double pulselength; 257 | pulselength = 1000000; // 1,000,000 us per second 258 | 259 | // Read prescale 260 | uint16_t prescale = readPrescale(); 261 | 262 | // Calculate the pulse for PWM based on Equation 1 from the datasheet section 263 | // 7.3.5 264 | prescale += 1; 265 | pulselength *= prescale; 266 | pulselength /= _oscillator_freq; 267 | 268 | 269 | 270 | pulse /= pulselength; 271 | 272 | 273 | setPWM(num, 0, pulse); 274 | } 275 | 276 | /*! 277 | * @brief Getter for the internally tracked oscillator used for freq 278 | * calculations 279 | * @returns The frequency the PCA9685 thinks it is running at (it cannot 280 | * introspect) 281 | */ 282 | uint32_t Adafruit_PWMServoDriver::getOscillatorFrequency(void) { 283 | return _oscillator_freq; 284 | } 285 | 286 | /*! 287 | * @brief Setter for the internally tracked oscillator used for freq 288 | * calculations 289 | * @param freq The frequency the PCA9685 should use for frequency calculations 290 | */ 291 | void Adafruit_PWMServoDriver::setOscillatorFrequency(uint32_t freq) { 292 | _oscillator_freq = freq; 293 | } 294 | 295 | /******************* Low level I2C interface */ 296 | uint8_t Adafruit_PWMServoDriver::read8(uint8_t addr) { 297 | return wiringPiI2CReadReg8(_fd,addr); 298 | } 299 | 300 | void Adafruit_PWMServoDriver::write8(uint8_t addr, uint8_t d) { 301 | wiringPiI2CWriteReg8(_fd,addr,d); 302 | } 303 | -------------------------------------------------------------------------------- /PCB/NixieAtomicClock.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 3.302, 37 | "height": 3.302, 38 | "width": 3.302 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.254 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | } 57 | ], 58 | "drc_exclusions": [], 59 | "meta": { 60 | "version": 1 61 | }, 62 | "rule_severities": { 63 | "annular_width": "error", 64 | "clearance": "error", 65 | "copper_edge_clearance": "error", 66 | "courtyards_overlap": "ignore", 67 | "diff_pair_gap_out_of_range": "error", 68 | "diff_pair_uncoupled_length_too_long": "error", 69 | "drill_too_small": "error", 70 | "duplicate_footprints": "warning", 71 | "extra_footprint": "warning", 72 | "hole_clearance": "error", 73 | "hole_near_hole": "error", 74 | "invalid_outline": "error", 75 | "item_on_disabled_layer": "error", 76 | "items_not_allowed": "error", 77 | "keepout": "error", 78 | "length_out_of_range": "error", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_too_small": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "error", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_over_copper": "ignore", 89 | "silk_overlap": "ignore", 90 | "skew_out_of_range": "error", 91 | "too_many_vias": "error", 92 | "track_dangling": "warning", 93 | "track_width": "error", 94 | "tracks_crossing": "error", 95 | "unconnected_items": "error", 96 | "unresolved_variable": "error", 97 | "via_dangling": "warning", 98 | "via_hole_larger_than_pad": "error", 99 | "zone_has_empty_net": "error", 100 | "zones_intersect": "error" 101 | }, 102 | "rules": { 103 | "allow_blind_buried_vias": false, 104 | "allow_microvias": false, 105 | "max_error": 0.005, 106 | "min_clearance": 0.127, 107 | "min_copper_edge_clearance": 0.0, 108 | "min_hole_to_hole": 0.25, 109 | "min_microvia_diameter": 0.19999999999999998, 110 | "min_microvia_drill": 0.09999999999999999, 111 | "min_silk_clearance": 0.0, 112 | "min_through_hole_diameter": 0.254, 113 | "min_track_width": 0.127, 114 | "min_via_annular_width": 0.1016, 115 | "min_via_diameter": 0.4572, 116 | "solder_mask_clearance": 0.0, 117 | "solder_mask_min_width": 0.0, 118 | "solder_paste_clearance": 0.0, 119 | "solder_paste_margin_ratio": -0.0 120 | }, 121 | "track_widths": [ 122 | 0.0, 123 | 0.127, 124 | 0.154, 125 | 0.2, 126 | 0.25, 127 | 0.3, 128 | 0.35, 129 | 0.4, 130 | 0.45, 131 | 0.5, 132 | 1.0, 133 | 1.2, 134 | 3.0 135 | ], 136 | "via_dimensions": [ 137 | { 138 | "diameter": 0.0, 139 | "drill": 0.0 140 | } 141 | ], 142 | "zones_allow_external_fillets": false, 143 | "zones_use_no_outline": true 144 | }, 145 | "layer_presets": [] 146 | }, 147 | "boards": [], 148 | "cvpcb": { 149 | "equivalence_files": [] 150 | }, 151 | "erc": { 152 | "meta": { 153 | "version": 0 154 | }, 155 | "pin_map": [ 156 | [ 157 | 0, 158 | 0, 159 | 0, 160 | 0, 161 | 0, 162 | 1, 163 | 0, 164 | 0, 165 | 0, 166 | 0, 167 | 2 168 | ], 169 | [ 170 | 0, 171 | 2, 172 | 0, 173 | 1, 174 | 0, 175 | 1, 176 | 0, 177 | 2, 178 | 2, 179 | 2, 180 | 2 181 | ], 182 | [ 183 | 0, 184 | 0, 185 | 0, 186 | 0, 187 | 0, 188 | 1, 189 | 0, 190 | 1, 191 | 0, 192 | 1, 193 | 2 194 | ], 195 | [ 196 | 0, 197 | 1, 198 | 0, 199 | 0, 200 | 0, 201 | 1, 202 | 1, 203 | 2, 204 | 1, 205 | 1, 206 | 2 207 | ], 208 | [ 209 | 0, 210 | 0, 211 | 0, 212 | 0, 213 | 0, 214 | 1, 215 | 0, 216 | 0, 217 | 0, 218 | 0, 219 | 2 220 | ], 221 | [ 222 | 1, 223 | 1, 224 | 1, 225 | 1, 226 | 1, 227 | 1, 228 | 1, 229 | 1, 230 | 1, 231 | 1, 232 | 2 233 | ], 234 | [ 235 | 0, 236 | 0, 237 | 0, 238 | 1, 239 | 0, 240 | 1, 241 | 0, 242 | 0, 243 | 0, 244 | 0, 245 | 2 246 | ], 247 | [ 248 | 0, 249 | 2, 250 | 1, 251 | 2, 252 | 0, 253 | 1, 254 | 0, 255 | 2, 256 | 2, 257 | 2, 258 | 2 259 | ], 260 | [ 261 | 0, 262 | 2, 263 | 0, 264 | 1, 265 | 0, 266 | 1, 267 | 0, 268 | 2, 269 | 0, 270 | 0, 271 | 2 272 | ], 273 | [ 274 | 0, 275 | 2, 276 | 1, 277 | 1, 278 | 0, 279 | 1, 280 | 0, 281 | 2, 282 | 0, 283 | 0, 284 | 2 285 | ], 286 | [ 287 | 2, 288 | 2, 289 | 2, 290 | 2, 291 | 2, 292 | 2, 293 | 2, 294 | 2, 295 | 2, 296 | 2, 297 | 2 298 | ] 299 | ], 300 | "rule_severities": { 301 | "bus_definition_conflict": "error", 302 | "bus_label_syntax": "error", 303 | "bus_to_bus_conflict": "error", 304 | "bus_to_net_conflict": "error", 305 | "different_unit_footprint": "error", 306 | "different_unit_net": "error", 307 | "duplicate_sheet_names": "error", 308 | "global_label_dangling": "warning", 309 | "hier_label_mismatch": "error", 310 | "label_dangling": "error", 311 | "lib_symbol_issues": "warning", 312 | "multiple_net_names": "warning", 313 | "net_not_bus_member": "warning", 314 | "no_connect_connected": "error", 315 | "no_connect_dangling": "error", 316 | "pin_not_connected": "error", 317 | "pin_not_driven": "error", 318 | "pin_to_pin": "warning", 319 | "similar_labels": "warning", 320 | "unresolved_variable": "error", 321 | "wire_dangling": "error" 322 | } 323 | }, 324 | "libraries": { 325 | "pinned_footprint_libs": [], 326 | "pinned_symbol_libs": [] 327 | }, 328 | "meta": { 329 | "filename": "NixieAtomicClock.kicad_pro", 330 | "version": 1 331 | }, 332 | "net_settings": { 333 | "classes": [ 334 | { 335 | "bus_width": 6.0, 336 | "clearance": 0.127, 337 | "diff_pair_gap": 0.2, 338 | "diff_pair_via_gap": 0.25, 339 | "diff_pair_width": 0.2, 340 | "line_style": 0, 341 | "microvia_diameter": 0.3, 342 | "microvia_drill": 0.1, 343 | "name": "Default", 344 | "pcb_color": "rgba(0, 0, 0, 0.000)", 345 | "schematic_color": "rgba(0, 0, 0, 0.000)", 346 | "track_width": 0.127, 347 | "via_diameter": 0.5032, 348 | "via_drill": 0.3, 349 | "wire_width": 6.0 350 | }, 351 | { 352 | "bus_width": 6.0, 353 | "clearance": 0.2, 354 | "diff_pair_gap": 0.2, 355 | "diff_pair_via_gap": 0.25, 356 | "diff_pair_width": 0.2, 357 | "line_style": 0, 358 | "microvia_diameter": 0.3, 359 | "microvia_drill": 0.1, 360 | "name": "Power", 361 | "nets": [ 362 | "ISENSE_SYS_N" 363 | ], 364 | "pcb_color": "rgba(0, 0, 0, 0.000)", 365 | "schematic_color": "rgba(0, 0, 0, 0.000)", 366 | "track_width": 1.2, 367 | "via_diameter": 0.5032, 368 | "via_drill": 0.3, 369 | "wire_width": 6.0 370 | } 371 | ], 372 | "meta": { 373 | "version": 0 374 | }, 375 | "net_colors": null 376 | }, 377 | "pcbnew": { 378 | "last_paths": { 379 | "gencad": "", 380 | "idf": "", 381 | "netlist": "", 382 | "specctra_dsn": "", 383 | "step": "8NixieClock.step", 384 | "vrml": "" 385 | }, 386 | "page_layout_descr_file": "" 387 | }, 388 | "schematic": { 389 | "drawing": { 390 | "default_bus_thickness": 12.0, 391 | "default_junction_size": 40.0, 392 | "default_line_thickness": 6.0, 393 | "default_text_size": 50.0, 394 | "default_wire_thickness": 6.0, 395 | "field_names": [], 396 | "intersheets_ref_prefix": "", 397 | "intersheets_ref_short": false, 398 | "intersheets_ref_show": false, 399 | "intersheets_ref_suffix": "", 400 | "pin_symbol_size": 25.0, 401 | "text_offset_ratio": 0.3 402 | }, 403 | "legacy_lib_dir": "", 404 | "legacy_lib_list": [], 405 | "meta": { 406 | "version": 0 407 | }, 408 | "net_format_name": "", 409 | "page_layout_descr_file": "empty.kicad_wks", 410 | "plot_directory": "", 411 | "spice_adjust_passive_values": false, 412 | "spice_external_command": "spice \"%I\"", 413 | "subpart_first_id": 65, 414 | "subpart_id_separator": 0 415 | }, 416 | "sheets": [ 417 | [ 418 | "bc5176a5-0c8b-4c87-a517-29dea9ca9db1", 419 | "" 420 | ] 421 | ], 422 | "text_variables": {} 423 | } 424 | -------------------------------------------------------------------------------- /RPI_Code/uploadClock.py: -------------------------------------------------------------------------------- 1 | import spidev 2 | import sys 3 | import RPi.GPIO as GPIO 4 | import time 5 | from threading import Event, Thread, Timer 6 | from influxdb import InfluxDBClient 7 | from multiprocessing import Queue 8 | import datetime 9 | import fcntl 10 | import subprocess 11 | import sys 12 | import random 13 | from dateutil import parser 14 | from dbSetting import * 15 | from struct import * 16 | 17 | spi_conf = spidev.SpiDev() 18 | spi_conf.open(0, 0) 19 | spi_conf.max_speed_hz = 6250000 20 | spi_conf.mode = 0b00 21 | 22 | GPIO.setmode(GPIO.BCM) 23 | 24 | previousToF = 0 25 | previousOffset = 0 26 | LastFPGATime = 0 27 | offset = 0 28 | Nextoffset = 0 29 | 30 | 31 | ##============FPGA Functions================## 32 | def writePWM(pwm): 33 | pwm = pwm.to_bytes(2, byteorder='big') 34 | pwm_high = pwm[1] 35 | pwm_low = pwm[0] 36 | spi_conf.xfer([10,pwm_low]) 37 | spi_conf.xfer([11,pwm_high]) 38 | 39 | def writePWMDivider(div): 40 | div = div.to_bytes(2, byteorder='big') 41 | div_high = div[1] 42 | div_low = div[0] 43 | spi_conf.xfer([12,div_low]) 44 | spi_conf.xfer([13,div_high]) 45 | 46 | def SequenceDigit(): 47 | #Enable Manual Control Nixie 48 | spi_conf.xfer([0,0x08]) 49 | #Clear Nixie DP 50 | spi_conf.xfer([8,0x08]) 51 | spi_conf.xfer([9,0x08]) 52 | for x in range(20): 53 | for digitno in range(10): 54 | data = [] 55 | for x in range(4): 56 | data.append( digitno*16 + digitno) 57 | pass 58 | spi_conf.xfer([4,data[0]]) 59 | spi_conf.xfer([5,data[1]]) 60 | spi_conf.xfer([6,data[2]]) 61 | spi_conf.xfer([7,data[3]]) 62 | time.sleep(0.05) 63 | #Disable Manual Control Nixie 64 | spi_conf.xfer([14,0x08]) 65 | Timer(3600 - int(time.localtime().tm_sec) + int(time.localtime().tm_min) * 60, SequenceDigit, ()).start() 66 | pass 67 | 68 | def randomDigit(): 69 | #Enable Manual Control Nixie 70 | spi_conf.xfer([0,0x08]) 71 | #Clear Nixie DP 72 | spi_conf.xfer([8,0x08]) 73 | spi_conf.xfer([9,0x08]) 74 | for x in range(200): 75 | data = [] 76 | for x in range(4): 77 | data.append( random.randint(0,9)*16 + random.randint(0,9)) 78 | pass 79 | spi_conf.xfer([4,data[0]]) 80 | spi_conf.xfer([5,data[1]]) 81 | spi_conf.xfer([6,data[2]]) 82 | spi_conf.xfer([7,data[3]]) 83 | time.sleep(0.02) 84 | #Disable Manual Control Nixie 85 | spi_conf.xfer([14,0x08]) 86 | Timer(3600 - int(time.localtime().tm_sec) + int(time.localtime().tm_min) * 60, randomDigit, ()).start() 87 | pass 88 | 89 | def writeConf(conf): 90 | spi_conf.xfer([0,conf]) 91 | 92 | def writeTime(h,m,s): 93 | h = h % 24 94 | m = m % 60 95 | s = s % 60 96 | spi_conf.xfer([0x01,s]) 97 | spi_conf.xfer([0x02,m]) 98 | spi_conf.xfer([0x03,h]) 99 | 100 | def readTOF(): 101 | data = spi_conf.xfer([0x01+128,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]) 102 | TDC_TIME1 = data[16]*65536 + data[15]*256 + data[14] 103 | TDC_TIME2 = data[13]*65536 + data[12]*256 + data[11] 104 | TDC_CLOCK_COUNT1 = data[10]*65536 + data[9]*256 + data[8] 105 | TDC_CALIBRATION1 = data[7]*65536 + data[6]*256 + data[5] 106 | TDC_CALIBRATION2 = data[4]*65536 + data[3]*256 + data[2] 107 | calCount = (TDC_CALIBRATION2 - TDC_CALIBRATION1) / 9 108 | normLSB = 1/10000000/calCount 109 | #output us 110 | print(TDC_TIME1,TDC_TIME2,TDC_CLOCK_COUNT1,calCount) 111 | return (TDC_TIME1-TDC_TIME2)/calCount+TDC_CLOCK_COUNT1 112 | 113 | def readFiFo(): 114 | fifo_count = spi_conf.xfer([128+2,0x00,0x00,0x00]) 115 | return fifo_count[3]*256 + fifo_count[2] 116 | 117 | def readTime(): 118 | fifo_count = spi_conf.xfer([128+4,0x00,0x00,0x00,0x00]) 119 | return fifo_count[4]*256*256 + fifo_count[3]*256 + fifo_count[2] 120 | 121 | def readPPSCourseCounter(): 122 | data = spi_conf.xfer([0x00+128,0x00,0x00,0x00,0x00,0x00]) 123 | return data[5]*16777216 + data[4]*65536 + data[3]*256 + data[2] 124 | 125 | def readFiFoOverflow(): 126 | fifo_count = spi_conf.xfer([128+5,0x00,0x00]) 127 | print(fifo_count) 128 | return fifo_count[2] 129 | 130 | ##============FPGA Functions END=============## 131 | 132 | ##============Upload To InfluxDB================## 133 | dataQueue = Queue(300) 134 | 135 | class uploadDataThread (Thread): 136 | def __init__(self, ifuser, ifpass, ifdb, ifhost, queue): 137 | Thread.__init__(self) 138 | self.ifuser = ifuser 139 | self.ifpass = ifpass 140 | self.ifdb = ifdb 141 | self.ifhost = ifhost 142 | self.ifport = ifport 143 | self.queue = queue 144 | 145 | def run(self): 146 | print("[Upload Thread] Starting") 147 | self.ifclient = InfluxDBClient(ifhost,ifport,ifuser,ifpass,ifdb,timeout=2,retries=3) 148 | while 1: 149 | val = self.queue.get() 150 | try: 151 | self.ifclient.write_points(val) 152 | except Exception as e: 153 | print(e) 154 | 155 | uploadDataThread(ifuser, ifpass, ifdb, ifhost, dataQueue).start() 156 | 157 | ##============Upload To InfluxDB END=============## 158 | 159 | 160 | #Setup - Close LED 161 | spi_conf.xfer([0,0x02]) 162 | 163 | #Setup - Align GPS PPS 164 | spi_conf.xfer([0,0x01]) 165 | time.sleep(3) 166 | spi_conf.xfer([14,0x01]) 167 | 168 | #Setup - Time 169 | timeNow = datetime.datetime.utcnow() + datetime.timedelta(hours=-7) + datetime.timedelta(seconds=1) 170 | writeTime(timeNow.hour,timeNow.minute,timeNow.second) 171 | 172 | 173 | ##============Polling FPGA Function=============## 174 | def readData(dataQueue): 175 | global previousToF 176 | global LastFPGATime 177 | global previousOffset 178 | global offset 179 | while 1: 180 | try: 181 | FPGATime = readTime() 182 | if(FPGATime == LastFPGATime): 183 | return 184 | time.sleep(0.3) 185 | FPGATime = readTime() 186 | print(FPGATime) 187 | ToF = readTOF() - 5000 188 | PPSCycle = readPPSCourseCounter() 189 | PPSDuration = (PPSCycle - ToF + previousToF) 190 | fifo = readFiFo() 191 | fifo_overflow_flag = readFiFoOverflow() 192 | print("%f,%d,%f,%d,%d" % (ToF,PPSCycle,PPSDuration,fifo,fifo_overflow_flag)) 193 | 194 | body2 = [ 195 | { 196 | "measurement": "FPGA", 197 | "time": datetime.datetime.utcnow(), 198 | "fields": { 199 | "GPS": PPSCycle, 200 | "Clock": ToF, 201 | "PPS Duration": PPSDuration, 202 | "FIFO Count": fifo, 203 | "FIFO Overrun": fifo_overflow_flag, 204 | "Adjusted Clock": PPSDuration+offset-previousOffset, 205 | "Adjusted ToF": ToF+offset 206 | } 207 | } 208 | ] 209 | print(body2) 210 | previousOffset = offset 211 | previousToF = ToF 212 | dataQueue.put(body2) 213 | LastFPGATime = FPGATime 214 | return 215 | except IOError: 216 | pass 217 | except Exception as e: 218 | print(e) 219 | pass 220 | 221 | def call_repeatedly(interval, func, *args): 222 | stopped = Event() 223 | print("[call_repeatedly] Starting") 224 | def loop(): 225 | while not stopped.wait(interval - time.time() % interval): # the first call is in `interval` secs 226 | func(*args) 227 | Thread(target=loop).start() 228 | return stopped.set 229 | 230 | time.sleep(1-time.time()%1) 231 | cancel_future_calls = call_repeatedly(0.2, readData, dataQueue) 232 | readData(dataQueue) 233 | ##============Polling FPGA Function END==========## 234 | 235 | 236 | ##============Timed Nixie Refresh Animate=============## 237 | #xx:30 min -> Random Digit Animate 238 | #xx:00 min -> Seq Digit Animate 239 | next_switch = 3600 - int(time.localtime().tm_sec) - (int(time.localtime().tm_min)*60) 240 | seq_digit = Timer(next_switch, SequenceDigit, ()) 241 | 242 | if time.localtime().tm_min>30: 243 | next_switch_random = (90 - int(time.localtime().tm_min)) * 60 - int(time.localtime().tm_sec) 244 | else: 245 | next_switch_random = (30 - int(time.localtime().tm_min)) * 60 - int(time.localtime().tm_sec) 246 | 247 | randomDigit_t = Timer(next_switch_random, randomDigit, ()) 248 | randomDigit_t.start() 249 | seq_digit.start() 250 | ##============Timed Nixie Refresh Animate END=============## 251 | 252 | 253 | ##Parsing UBX Package 254 | def Checksum(data): 255 | a = 0x00 256 | b = 0x00 257 | for byte in data: 258 | i = byte 259 | a += i 260 | b += a 261 | a &= 0xff 262 | b &= 0xff 263 | return b*256 + a 264 | 265 | flag_UBX = False 266 | 267 | try: 268 | while 1: 269 | data = sys.stdin.buffer.read(1) 270 | if data == b'\xB5': 271 | flag_UBX = True 272 | 273 | SYNC = sys.stdin.buffer.read(1) 274 | 275 | if SYNC != b'\x62': 276 | continue 277 | 278 | CLASS = sys.stdin.buffer.read(1) 279 | ID = sys.stdin.buffer.read(1) 280 | #print("[GPS Parse]",SYNC,CLASS,ID) 281 | LENGTH = sys.stdin.buffer.read(2) 282 | (length,) = unpack('H', LENGTH) 283 | 284 | #print(SYNC,CLASS,ID,LENGTH) 285 | 286 | PAYLOAD = sys.stdin.buffer.read(length) 287 | 288 | CHECKSUM = sys.stdin.buffer.read(2) 289 | (msgCksum,) = unpack('H',CHECKSUM) 290 | #print ('{:02x}'.format(msgCksum)) 291 | 292 | DATA = CLASS+ID+LENGTH+PAYLOAD 293 | print (''.join(format(x, '02x') for x in DATA)) 294 | 295 | if CLASS == b'\x0D' and ID == b'\x01': #TIM_TP 296 | try: 297 | (towMS,towSubMS,qErr,week,flags,refInfo) = unpack('IIiHBB', PAYLOAD) 298 | print (''.join(format(x, '02x') for x in PAYLOAD)) 299 | 300 | trueCksum = Checksum(DATA) 301 | print(towMS,towSubMS,qErr,week,flags,refInfo) 302 | 303 | if trueCksum != msgCksum: 304 | raise Exception( 305 | "Calculated checksum 0x{:02x} does not match 0x{:02x}." 306 | .format(trueCksum,msgCksum) 307 | ) 308 | qErrStr = str(time.time()) + "," + str(qErr) 309 | qErrStr = qErrStr.encode() 310 | print(qErrStr) 311 | body = [ 312 | { 313 | "measurement": "GPS", 314 | "time": datetime.datetime.utcnow(), 315 | "fields": { 316 | "Next Clock Offset": qErr 317 | } 318 | } 319 | ] 320 | print(body) 321 | dataQueue.put(body) 322 | offset = Nextoffset 323 | Nextoffset = float(qErr)/100000 324 | 325 | except Exception as e: 326 | print(e) 327 | print(CLASS+ID+PAYLOAD) 328 | body = [ 329 | { 330 | "measurement": "GPS", 331 | "time": datetime.datetime.utcnow(), 332 | "fields": { 333 | "Next Clock Offset": 0 334 | } 335 | } 336 | ] 337 | print(body) 338 | dataQueue.put(body) 339 | offset = 0 340 | pass 341 | 342 | except KeyboardInterrupt: 343 | sys.exit() -------------------------------------------------------------------------------- /RPI_Code/autoBrightness/Adafruit-PWM-Servo-Driver-Library-master/Adafruit_PWMServoDriver.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_PWMServoDriver.cpp 3 | * 4 | * @mainpage Adafruit 16-channel PWM & Servo driver 5 | * 6 | * @section intro_sec Introduction 7 | * 8 | * This is a library for the 16-channel PWM & Servo driver. 9 | * 10 | * Designed specifically to work with the Adafruit PWM & Servo driver. 11 | * 12 | * Pick one up today in the adafruit shop! 13 | * ------> https://www.adafruit.com/product/815 14 | * 15 | * These displays use I2C to communicate, 2 pins are required to interface. 16 | * 17 | * Adafruit invests time and resources providing this open source code, 18 | * please support Adafruit andopen-source hardware by purchasing products 19 | * from Adafruit! 20 | * 21 | * @section author Author 22 | * 23 | * Limor Fried/Ladyada (Adafruit Industries). 24 | * 25 | * @section license License 26 | * 27 | * BSD license, all text above must be included in any redistribution 28 | */ 29 | 30 | #include "Adafruit_PWMServoDriver.h" 31 | #include 32 | 33 | //#define ENABLE_DEBUG_OUTPUT 34 | 35 | /*! 36 | * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a 37 | * TwoWire interface 38 | */ 39 | Adafruit_PWMServoDriver::Adafruit_PWMServoDriver() 40 | : _i2caddr(PCA9685_I2C_ADDRESS), _i2c(&Wire) {} 41 | 42 | /*! 43 | * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a 44 | * TwoWire interface 45 | * @param addr The 7-bit I2C address to locate this chip, default is 0x40 46 | */ 47 | Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr) 48 | : _i2caddr(addr), _i2c(&Wire) {} 49 | 50 | /*! 51 | * @brief Instantiates a new PCA9685 PWM driver chip with the I2C address on a 52 | * TwoWire interface 53 | * @param addr The 7-bit I2C address to locate this chip, default is 0x40 54 | * @param i2c A reference to a 'TwoWire' object that we'll use to communicate 55 | * with 56 | */ 57 | Adafruit_PWMServoDriver::Adafruit_PWMServoDriver(const uint8_t addr, 58 | TwoWire &i2c) 59 | : _i2caddr(addr), _i2c(&i2c) {} 60 | 61 | /*! 62 | * @brief Setups the I2C interface and hardware 63 | * @param prescale 64 | * Sets External Clock (Optional) 65 | */ 66 | void Adafruit_PWMServoDriver::begin(uint8_t prescale) { 67 | _i2c->begin(); 68 | reset(); 69 | if (prescale) { 70 | setExtClk(prescale); 71 | } else { 72 | // set a default frequency 73 | setPWMFreq(1000); 74 | } 75 | // set the default internal frequency 76 | setOscillatorFrequency(FREQUENCY_OSCILLATOR); 77 | } 78 | 79 | /*! 80 | * @brief Sends a reset command to the PCA9685 chip over I2C 81 | */ 82 | void Adafruit_PWMServoDriver::reset() { 83 | write8(PCA9685_MODE1, MODE1_RESTART); 84 | delay(10); 85 | } 86 | 87 | /*! 88 | * @brief Puts board into sleep mode 89 | */ 90 | void Adafruit_PWMServoDriver::sleep() { 91 | uint8_t awake = read8(PCA9685_MODE1); 92 | uint8_t sleep = awake | MODE1_SLEEP; // set sleep bit high 93 | write8(PCA9685_MODE1, sleep); 94 | delay(5); // wait until cycle ends for sleep to be active 95 | } 96 | 97 | /*! 98 | * @brief Wakes board from sleep 99 | */ 100 | void Adafruit_PWMServoDriver::wakeup() { 101 | uint8_t sleep = read8(PCA9685_MODE1); 102 | uint8_t wakeup = sleep & ~MODE1_SLEEP; // set sleep bit low 103 | write8(PCA9685_MODE1, wakeup); 104 | } 105 | 106 | /*! 107 | * @brief Sets EXTCLK pin to use the external clock 108 | * @param prescale 109 | * Configures the prescale value to be used by the external clock 110 | */ 111 | void Adafruit_PWMServoDriver::setExtClk(uint8_t prescale) { 112 | uint8_t oldmode = read8(PCA9685_MODE1); 113 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 114 | write8(PCA9685_MODE1, newmode); // go to sleep, turn off internal oscillator 115 | 116 | // This sets both the SLEEP and EXTCLK bits of the MODE1 register to switch to 117 | // use the external clock. 118 | write8(PCA9685_MODE1, (newmode |= MODE1_EXTCLK)); 119 | 120 | write8(PCA9685_PRESCALE, prescale); // set the prescaler 121 | 122 | delay(5); 123 | // clear the SLEEP bit to start 124 | write8(PCA9685_MODE1, (newmode & ~MODE1_SLEEP) | MODE1_RESTART | MODE1_AI); 125 | 126 | #ifdef ENABLE_DEBUG_OUTPUT 127 | Serial.print("Mode now 0x"); 128 | Serial.println(read8(PCA9685_MODE1), HEX); 129 | #endif 130 | } 131 | 132 | /*! 133 | * @brief Sets the PWM frequency for the entire chip, up to ~1.6 KHz 134 | * @param freq Floating point frequency that we will attempt to match 135 | */ 136 | void Adafruit_PWMServoDriver::setPWMFreq(float freq) { 137 | #ifdef ENABLE_DEBUG_OUTPUT 138 | Serial.print("Attempting to set freq "); 139 | Serial.println(freq); 140 | #endif 141 | // Range output modulation frequency is dependant on oscillator 142 | if (freq < 1) 143 | freq = 1; 144 | if (freq > 3500) 145 | freq = 3500; // Datasheet limit is 3052=50MHz/(4*4096) 146 | 147 | float prescaleval = ((_oscillator_freq / (freq * 4096.0)) + 0.5) - 1; 148 | if (prescaleval < PCA9685_PRESCALE_MIN) 149 | prescaleval = PCA9685_PRESCALE_MIN; 150 | if (prescaleval > PCA9685_PRESCALE_MAX) 151 | prescaleval = PCA9685_PRESCALE_MAX; 152 | uint8_t prescale = (uint8_t)prescaleval; 153 | 154 | #ifdef ENABLE_DEBUG_OUTPUT 155 | Serial.print("Final pre-scale: "); 156 | Serial.println(prescale); 157 | #endif 158 | 159 | uint8_t oldmode = read8(PCA9685_MODE1); 160 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 161 | write8(PCA9685_MODE1, newmode); // go to sleep 162 | write8(PCA9685_PRESCALE, prescale); // set the prescaler 163 | write8(PCA9685_MODE1, oldmode); 164 | delay(5); 165 | // This sets the MODE1 register to turn on auto increment. 166 | write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI); 167 | 168 | #ifdef ENABLE_DEBUG_OUTPUT 169 | Serial.print("Mode now 0x"); 170 | Serial.println(read8(PCA9685_MODE1), HEX); 171 | #endif 172 | } 173 | 174 | /*! 175 | * @brief Sets the output mode of the PCA9685 to either 176 | * open drain or push pull / totempole. 177 | * Warning: LEDs with integrated zener diodes should 178 | * only be driven in open drain mode. 179 | * @param totempole Totempole if true, open drain if false. 180 | */ 181 | void Adafruit_PWMServoDriver::setOutputMode(bool totempole) { 182 | uint8_t oldmode = read8(PCA9685_MODE2); 183 | uint8_t newmode; 184 | if (totempole) { 185 | newmode = oldmode | MODE2_OUTDRV; 186 | } else { 187 | newmode = oldmode & ~MODE2_OUTDRV; 188 | } 189 | write8(PCA9685_MODE2, newmode); 190 | #ifdef ENABLE_DEBUG_OUTPUT 191 | Serial.print("Setting output mode: "); 192 | Serial.print(totempole ? "totempole" : "open drain"); 193 | Serial.print(" by setting MODE2 to "); 194 | Serial.println(newmode); 195 | #endif 196 | } 197 | 198 | /*! 199 | * @brief Reads set Prescale from PCA9685 200 | * @return prescale value 201 | */ 202 | uint8_t Adafruit_PWMServoDriver::readPrescale(void) { 203 | return read8(PCA9685_PRESCALE); 204 | } 205 | 206 | /*! 207 | * @brief Gets the PWM output of one of the PCA9685 pins 208 | * @param num One of the PWM output pins, from 0 to 15 209 | * @return requested PWM output value 210 | */ 211 | uint8_t Adafruit_PWMServoDriver::getPWM(uint8_t num) { 212 | _i2c->requestFrom((int)_i2caddr, PCA9685_LED0_ON_L + 4 * num, (int)4); 213 | return _i2c->read(); 214 | } 215 | 216 | /*! 217 | * @brief Sets the PWM output of one of the PCA9685 pins 218 | * @param num One of the PWM output pins, from 0 to 15 219 | * @param on At what point in the 4096-part cycle to turn the PWM output ON 220 | * @param off At what point in the 4096-part cycle to turn the PWM output OFF 221 | */ 222 | void Adafruit_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) { 223 | #ifdef ENABLE_DEBUG_OUTPUT 224 | Serial.print("Setting PWM "); 225 | Serial.print(num); 226 | Serial.print(": "); 227 | Serial.print(on); 228 | Serial.print("->"); 229 | Serial.println(off); 230 | #endif 231 | 232 | _i2c->beginTransmission(_i2caddr); 233 | _i2c->write(PCA9685_LED0_ON_L + 4 * num); 234 | _i2c->write(on); 235 | _i2c->write(on >> 8); 236 | _i2c->write(off); 237 | _i2c->write(off >> 8); 238 | _i2c->endTransmission(); 239 | } 240 | 241 | /*! 242 | * @brief Helper to set pin PWM output. Sets pin without having to deal with 243 | * on/off tick placement and properly handles a zero value as completely off and 244 | * 4095 as completely on. Optional invert parameter supports inverting the 245 | * pulse for sinking to ground. 246 | * @param num One of the PWM output pins, from 0 to 15 247 | * @param val The number of ticks out of 4096 to be active, should be a value 248 | * from 0 to 4095 inclusive. 249 | * @param invert If true, inverts the output, defaults to 'false' 250 | */ 251 | void Adafruit_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert) { 252 | // Clamp value between 0 and 4095 inclusive. 253 | val = min(val, (uint16_t)4095); 254 | if (invert) { 255 | if (val == 0) { 256 | // Special value for signal fully on. 257 | setPWM(num, 4096, 0); 258 | } else if (val == 4095) { 259 | // Special value for signal fully off. 260 | setPWM(num, 0, 4096); 261 | } else { 262 | setPWM(num, 0, 4095 - val); 263 | } 264 | } else { 265 | if (val == 4095) { 266 | // Special value for signal fully on. 267 | setPWM(num, 4096, 0); 268 | } else if (val == 0) { 269 | // Special value for signal fully off. 270 | setPWM(num, 0, 4096); 271 | } else { 272 | setPWM(num, 0, val); 273 | } 274 | } 275 | } 276 | 277 | /*! 278 | * @brief Sets the PWM output of one of the PCA9685 pins based on the input 279 | * microseconds, output is not precise 280 | * @param num One of the PWM output pins, from 0 to 15 281 | * @param Microseconds The number of Microseconds to turn the PWM output ON 282 | */ 283 | void Adafruit_PWMServoDriver::writeMicroseconds(uint8_t num, 284 | uint16_t Microseconds) { 285 | #ifdef ENABLE_DEBUG_OUTPUT 286 | Serial.print("Setting PWM Via Microseconds on output"); 287 | Serial.print(num); 288 | Serial.print(": "); 289 | Serial.print(Microseconds); 290 | Serial.println("->"); 291 | #endif 292 | 293 | double pulse = Microseconds; 294 | double pulselength; 295 | pulselength = 1000000; // 1,000,000 us per second 296 | 297 | // Read prescale 298 | uint16_t prescale = readPrescale(); 299 | 300 | #ifdef ENABLE_DEBUG_OUTPUT 301 | Serial.print(prescale); 302 | Serial.println(" PCA9685 chip prescale"); 303 | #endif 304 | 305 | // Calculate the pulse for PWM based on Equation 1 from the datasheet section 306 | // 7.3.5 307 | prescale += 1; 308 | pulselength *= prescale; 309 | pulselength /= _oscillator_freq; 310 | 311 | #ifdef ENABLE_DEBUG_OUTPUT 312 | Serial.print(pulselength); 313 | Serial.println(" us per bit"); 314 | #endif 315 | 316 | pulse /= pulselength; 317 | 318 | #ifdef ENABLE_DEBUG_OUTPUT 319 | Serial.print(pulse); 320 | Serial.println(" pulse for PWM"); 321 | #endif 322 | 323 | setPWM(num, 0, pulse); 324 | } 325 | 326 | /*! 327 | * @brief Getter for the internally tracked oscillator used for freq 328 | * calculations 329 | * @returns The frequency the PCA9685 thinks it is running at (it cannot 330 | * introspect) 331 | */ 332 | uint32_t Adafruit_PWMServoDriver::getOscillatorFrequency(void) { 333 | return _oscillator_freq; 334 | } 335 | 336 | /*! 337 | * @brief Setter for the internally tracked oscillator used for freq 338 | * calculations 339 | * @param freq The frequency the PCA9685 should use for frequency calculations 340 | */ 341 | void Adafruit_PWMServoDriver::setOscillatorFrequency(uint32_t freq) { 342 | _oscillator_freq = freq; 343 | } 344 | 345 | /******************* Low level I2C interface */ 346 | uint8_t Adafruit_PWMServoDriver::read8(uint8_t addr) { 347 | _i2c->beginTransmission(_i2caddr); 348 | _i2c->write(addr); 349 | _i2c->endTransmission(); 350 | 351 | _i2c->requestFrom((uint8_t)_i2caddr, (uint8_t)1); 352 | return _i2c->read(); 353 | } 354 | 355 | void Adafruit_PWMServoDriver::write8(uint8_t addr, uint8_t d) { 356 | _i2c->beginTransmission(_i2caddr); 357 | _i2c->write(addr); 358 | _i2c->write(d); 359 | _i2c->endTransmission(); 360 | } 361 | -------------------------------------------------------------------------------- /RPI_Code/readADC/readADC.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | // File Related Var 27 | char *folder; 28 | FILE *ADCFile; 29 | FILE *FreqFile; 30 | bool changed_FreqFile,changed_ADCFile; 31 | 32 | // Calculate Freq, Vrms, Max, Low Voltage Related Var 33 | bool positive_flag = 0; 34 | uint16_t last_timestamp = 0; 35 | double last_timestamp_fp = 0; 36 | double last_adc_voltage = 0; 37 | double heighest_voltage = 0; 38 | double lowset_voltage = 0; 39 | double rms_voltage_square_sum = 0; 40 | int rms_voltage_count = 0; 41 | 42 | // FPGA data Related Var 43 | uint16_t *read_count; 44 | uint32_t *secondsOfDay; 45 | uint16_t *pps_timestamp; 46 | char *buf_data; 47 | 48 | //FIFO Related Var 49 | volatile uint16_t *queue_write; 50 | volatile uint16_t *queue_read; 51 | const uint16_t queue_length = 3000; 52 | 53 | //Read FIFO FPGA CMD 54 | const char buf_readFIFO[9] = {128+2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 55 | 56 | //Init SPIdev 57 | int spi_init(char filename[40]){ 58 | int file; 59 | 60 | if ((file = open(filename,O_RDWR)) < 0) 61 | { 62 | printf("Failed to open the bus."); 63 | /* ERROR HANDLING; you can check errno to see what went wrong */ 64 | exit(1); 65 | } 66 | return file; 67 | } 68 | 69 | //Clear FPGA FIFO 70 | void setup_fifo(int file, struct spi_ioc_transfer xfer_conf){ 71 | int status; 72 | char buf[2] = {0x00,0x04}; 73 | //xfer.tx_buf = (unsigned long) buf_out; 74 | //xfer.len = 4; /* Length of command to write*/ 75 | xfer_conf.rx_buf = (unsigned long) NULL; 76 | xfer_conf.tx_buf = (unsigned long) buf; 77 | xfer_conf.len = 2; /* Length of Data to read */ 78 | 79 | status = ioctl(file, SPI_IOC_MESSAGE(1), &xfer_conf); 80 | if (status < 0) { 81 | perror("SPI_IOC_MESSAGE"); 82 | return ; 83 | } 84 | } 85 | 86 | //Write Frequency to File 87 | void writeFrequency(uint16_t timestamp, double frequency, double rms_voltage){ 88 | time_t current_time; 89 | struct tm * time_info; 90 | char buffer[200] = {0}; 91 | 92 | time_t s; // Seconds 93 | struct timespec spec; 94 | clock_gettime(CLOCK_REALTIME, &spec); 95 | s = spec.tv_sec; 96 | sprintf(buffer, "%"PRIdMAX".%09ld,%d,%f,%f\n",(intmax_t)s, spec.tv_nsec,timestamp,frequency,rms_voltage); 97 | 98 | fwrite(buffer,1,strlen(buffer),FreqFile); 99 | time(¤t_time); 100 | time_info = localtime(¤t_time); 101 | if ((time_info->tm_min % 5 == 0) & (changed_FreqFile == 0)) //Switch file per 5 min 102 | { 103 | char timeString[100] = {0}; 104 | char fileString[100] = {0}; 105 | strftime(timeString, sizeof(timeString), "ACFREQ_%Y%m%d_%H%M%S.txt", time_info); 106 | sprintf(fileString,"%s%s",folder,timeString); 107 | 108 | fclose(FreqFile); 109 | FreqFile = fopen(fileString,"w" ); 110 | changed_FreqFile = 1; 111 | } 112 | if ((time_info->tm_min % 5 == 1) & (changed_FreqFile == 1)) 113 | { 114 | changed_FreqFile = 0; 115 | } 116 | } 117 | 118 | //Process ADC raw data from FPGA 119 | void process_data(int length, uint8_t* buf_in){ 120 | for (int k=0;k heighest_voltage) heighest_voltage = voltage; 129 | if(voltage < lowset_voltage) lowset_voltage = voltage; 130 | char buffer[200] = {0}; 131 | //ASCII Format 132 | //sprintf(buffer, "%d,%d,%d,%d,%f\n",*secondsOfDay,fifo,timestamp,adc_data,voltage); 133 | //printf("%s",buffer); 134 | //fwrite(buffer,1,strlen(buffer),ADCFile); 135 | 136 | //Binary File Format 137 | memcpy(buffer,secondsOfDay,sizeof(uint32_t)); 138 | memcpy(buffer+4,read_count,sizeof(uint32_t)); 139 | memcpy(buffer+8,×tamp,sizeof(uint16_t)); 140 | memcpy(buffer+10,&adc_data,sizeof(uint16_t)); 141 | fwrite(buffer,1,12,ADCFile); 142 | 143 | if ( voltage>0 && positive_flag == 0 ){ //Zero corssing from negitive to positive 144 | double current_timestamp_fp = -1 * last_adc_voltage / (voltage - last_adc_voltage); 145 | uint16_t timestamp_duration = 0; 146 | if(timestamp0); 165 | last_adc_voltage = voltage; 166 | } 167 | } 168 | } 169 | 170 | 171 | void main(int argc, char *argv[]){ 172 | folder = argv[1]; 173 | 174 | // Share Memory for Thread communication 175 | int shm_id; 176 | shm_id = shmget(IPC_PRIVATE, 12+3000*16, IPC_CREAT | 0666); 177 | if (shm_id < 0) { 178 | printf("shmget error\n"); 179 | exit(1); 180 | } 181 | 182 | // Forking two thread - Reading and Processing 183 | pid_t child_a, child_b; 184 | child_a = fork(); 185 | 186 | if (child_a == 0) { 187 | /* Child code */ 188 | printf("Read Thread Start\n"); 189 | 190 | //Get the share memory 191 | char *shm_addr; 192 | shm_addr = shmat(shm_id, NULL, 0); 193 | if (shm_addr == (char *)(-1)) { 194 | perror("shmat"); 195 | exit(1); 196 | } 197 | 198 | //Start of the SHM is the pointer of FIFO and FPGA data 199 | queue_write = (uint16_t*)shm_addr; 200 | queue_read = (uint16_t*)shm_addr + 2; 201 | 202 | read_count = (uint16_t*)shm_addr + 4; 203 | secondsOfDay = (uint32_t*)shm_addr + 6; 204 | pps_timestamp = (uint16_t*)shm_addr + 10; 205 | 206 | //FIFO Data is after this 207 | buf_data = (char*)shm_addr + 64; 208 | 209 | //Set write point to 0 210 | *queue_write = 0; 211 | 212 | //Lock the reading thread to CPU 2 only 213 | cpu_set_t mask; 214 | CPU_ZERO(&mask); 215 | CPU_SET(2, &mask); 216 | int result = sched_setaffinity(0, sizeof(mask), &mask); 217 | 218 | 219 | //INIT SPI 220 | char buf_in_DATA[255*16+2]; 221 | char buf_in_FIFO[9] = {0}; 222 | int file=spi_init("/dev/spidev0.1"); 223 | int file_conf=spi_init("/dev/spidev0.0"); 224 | 225 | int mode = SPI_MODE_0; 226 | ioctl(file,SPI_IOC_WR_MODE,&mode); 227 | 228 | struct spi_ioc_transfer xfer[2]; 229 | struct spi_ioc_transfer xfer_conf; 230 | memset((void*)&xfer_conf,0,sizeof(xfer_conf)); 231 | memset((void*)xfer,0,sizeof(xfer)); 232 | 233 | xfer[0].len = 4; 234 | xfer[0].cs_change = 0; 235 | xfer[0].delay_usecs = 0, 236 | xfer[0].speed_hz = 12500000, 237 | xfer[0].bits_per_word = 8, 238 | 239 | xfer[1].len = 4; 240 | xfer[1].cs_change = 0; 241 | xfer[1].delay_usecs = 0, 242 | xfer[1].speed_hz = 12500000, 243 | xfer[1].bits_per_word = 8, 244 | 245 | xfer_conf.len = 4; 246 | xfer_conf.cs_change = 0; 247 | xfer_conf.delay_usecs = 0, 248 | xfer_conf.speed_hz = 6250000, 249 | xfer_conf.bits_per_word = 8, 250 | 251 | //CLEAR FIFO 252 | setup_fifo(file_conf,xfer_conf); 253 | 254 | while(1){ 255 | //Read FIFO count, ADC_Tag, Current Time 256 | xfer_conf.rx_buf = (unsigned long) buf_in_FIFO; 257 | xfer_conf.tx_buf = (unsigned long) buf_readFIFO; 258 | xfer_conf.len = 9; 259 | 260 | int status = ioctl(file_conf, SPI_IOC_MESSAGE(1), &xfer_conf); 261 | if (status < 0) 262 | { 263 | perror("SPI_IOC_MESSAGE"); 264 | return; 265 | } 266 | //printf("env: %02x %02x %02x %02x %02x\n", buf_out[0], buf_out[1], buf_out[2], buf_out[3],buf_out[4]); 267 | //printf("ret: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", buf_in_2[0], buf_in_2[1], buf_in_2[2], buf_in_2[3], buf_in_2[4], buf_in_2[5], buf_in_2[6], buf_in_2[7], buf_in_2[8]); 268 | 269 | *read_count = buf_in_FIFO[3]*256+buf_in_FIFO[2]; 270 | *secondsOfDay = (int)buf_in_FIFO[8]*3600+(int)buf_in_FIFO[7]*60+(int)buf_in_FIFO[6]; 271 | *pps_timestamp = buf_in_FIFO[5]*256+buf_in_FIFO[4]; 272 | 273 | //printf("Reading....%d,%d,%d\n",*read_count,*pps_timestamp,*secondsOfDay); 274 | 275 | //If FIFO count is not zero then read the indicated amount 276 | if (*read_count == 0) continue; 277 | int transferCount = *read_count > 255 ? 255 : *read_count; 278 | 279 | xfer[0].rx_buf = (unsigned long) buf_in_DATA; 280 | xfer[0].tx_buf = (unsigned long) NULL; 281 | xfer[0].len = transferCount*16 + 2; 282 | 283 | //printf("Reading....%d\n",transferCount); 284 | status = ioctl(file, SPI_IOC_MESSAGE(1), &xfer); 285 | if (status < 0){ 286 | perror("SPI_IOC_MESSAGE"); 287 | return; 288 | } 289 | 290 | //Put to SHM and advance write pointer 291 | memcpy(buf_data+*queue_write*16,buf_in_DATA+2,transferCount*16); 292 | int queue_write_next = (*queue_write+transferCount)%queue_length; 293 | //*queue_write += transferCount; 294 | *queue_write = queue_write_next; 295 | 296 | //Clear SPI buffer 297 | memset(buf_in_DATA,0,sizeof(buf_in_DATA)); 298 | } 299 | } 300 | else { 301 | printf("Process Thread Start\n"); 302 | 303 | //Open file with timestamp 304 | time_t current_time; 305 | struct tm * time_info; 306 | time(¤t_time); 307 | time_info = localtime(¤t_time); 308 | 309 | char timeString[100] = {0}; 310 | strftime(timeString, sizeof(timeString), "Waveform_%Y%m%d_%H%M%S.bin", time_info); 311 | char fileString[100] = {0}; 312 | sprintf(fileString,"%s%s",folder,timeString); 313 | printf("Write to: %s\n",fileString); 314 | ADCFile = fopen( fileString,"w"); 315 | //fcntl(ADCFile, F_SETFL, O_NONBLOCK); 316 | 317 | strftime(timeString, sizeof(timeString), "ACFREQ_%Y%m%d_%H%M%S.txt", time_info); 318 | sprintf(fileString,"%s%s",folder,timeString); 319 | printf("Write to: %s\n",fileString); 320 | FreqFile = fopen(fileString,"w"); 321 | 322 | int current_fileSecond = 0; 323 | 324 | //Open SHM 325 | char *shm_addr; 326 | shm_addr = shmat(shm_id, NULL, 0); 327 | if (shm_addr == (char *)(-1)) { 328 | perror("shmat"); 329 | exit(1); 330 | } 331 | 332 | queue_write = (uint16_t*)shm_addr; 333 | queue_read = (uint16_t*)shm_addr + 2; 334 | 335 | read_count = (uint16_t*)shm_addr + 4; 336 | secondsOfDay = (uint32_t*)shm_addr + 6; 337 | pps_timestamp = (uint16_t*)shm_addr + 10; 338 | 339 | buf_data = shm_addr + 64; 340 | 341 | //Setup read pointer 342 | *queue_read = 0; 343 | 344 | while(1){ 345 | if(*queue_read == *queue_write){ 346 | //printf("Processing....%d,%d\n",*queue_read,*queue_write); 347 | usleep(1000*20); 348 | continue; 349 | } 350 | int queue_write_backup = *queue_write; 351 | //printf("Processing....%d,%d\n",*queue_read,queue_write_backup); 352 | if(*queue_read > queue_write_backup){ 353 | int read_size = queue_length - *queue_read; 354 | process_data(read_size, buf_data+*queue_read*16); 355 | read_size = queue_write_backup; 356 | process_data(read_size, buf_data); 357 | } 358 | else{ 359 | int read_size = queue_write_backup - *queue_read; 360 | process_data(read_size, buf_data+*queue_read*16); 361 | } 362 | *queue_read = queue_write_backup; 363 | 364 | if(*secondsOfDay % 60 == 0 && current_fileSecond != *secondsOfDay){ 365 | fclose(ADCFile); 366 | time_t current_time; 367 | struct tm * time_info; 368 | time(¤t_time); 369 | time_info = localtime(¤t_time); 370 | 371 | int hour = *secondsOfDay/3600; 372 | int minute = (*secondsOfDay/60)%60; 373 | int seconds = *secondsOfDay%60; 374 | 375 | char dateString[100] = {0}; 376 | strftime(dateString, sizeof(dateString), "Waveform_%Y%m%d_", time_info); 377 | char timeString[100] = {0}; 378 | sprintf(timeString,"%02d%02d%02d.bin",hour,minute,seconds); 379 | char fileString[100] = {0}; 380 | sprintf(fileString,"%s%s%s",folder,dateString,timeString); 381 | printf("Write to: %s\n",fileString); 382 | ADCFile = fopen(fileString,"w"); 383 | current_fileSecond = *secondsOfDay; 384 | } 385 | } 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /FPGA/main.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | module main ( 4 | input CLOCK, 5 | input CLOCK2, 6 | 7 | //SPI to RPI 8 | input MOSI, 9 | input CS, 10 | input SCK, 11 | output MISO, 12 | 13 | //RPI GPIO 14 | output IOB_16, 15 | output IOB_18, 16 | input IOB_20, 17 | 18 | //PPS OUT 19 | output PPS_OUT2, 20 | output PPS_OUT, 21 | 22 | //TDC7200 23 | output TDC_CS, 24 | output TDC_SCLK, 25 | output TDC_MOSI, 26 | input TDC_MISO, 27 | input TDC_START, 28 | output TDC_STOP, 29 | input TDC_TRIG, 30 | output TDC_EN, 31 | input TDC_INT, 32 | 33 | //NIXIE Clock 34 | output NIXIE_CLK, 35 | output NIXIE_DIN, 36 | output NIXIE_LE, 37 | output NIXIE_BL, 38 | output NIXIE_POL, 39 | 40 | //MAC Lock 41 | input MAC_LOCK, 42 | 43 | //LEDs 44 | output pin_ledR, 45 | output pin_ledG, 46 | output pin_ledB, 47 | 48 | //ADC 49 | output ADC_CS, 50 | output ADC_SCLK, 51 | output ADC_MOSI, 52 | input ADC_MISO, 53 | 54 | //DEBUG 55 | output IOB_2, 56 | output IOB_0, 57 | output IOB_3, 58 | output IOB_49, 59 | output IOB_51 60 | ); 61 | 62 | wire CLOCK_BUF; 63 | SB_GB SB_GB( 64 | .USER_SIGNAL_TO_GLOBAL_BUFFER(CLOCK), 65 | .GLOBAL_BUFFER_OUTPUT(CLOCK_BUF) 66 | ); 67 | 68 | wire reset; 69 | reg [3:0] resetn_counter = 0; 70 | assign reset = &resetn_counter; 71 | 72 | always @(posedge CLOCK) begin 73 | if (!reset) 74 | resetn_counter <= resetn_counter + 1; 75 | end 76 | 77 | reg [23:0] pps_counterval; 78 | always @(posedge reset) begin 79 | pps_counterval<= 24'h98967F; 80 | end 81 | 82 | 83 | wire pps_out; 84 | wire align_GPS; 85 | reg align_GPS_startup,align_GPS_startup_next; 86 | 87 | //Capture Rising Pulse from PPS 88 | wire GPS_PPS = TDC_START; 89 | reg GPS_PPS_d; 90 | always @(posedge CLOCK_BUF) begin 91 | GPS_PPS_d <= GPS_PPS; 92 | end 93 | 94 | 95 | wire rst_ppscounter = ~((GPS_PPS & (~GPS_PPS_d)) & (align_GPS)) & reset; 96 | wire pps_pulse; 97 | pulsepersecond fpga_pps( 98 | .clk_in(CLOCK_BUF), 99 | .clk_out(pps_pulse), 100 | .pps_out(pps_out), 101 | .counter_value(pps_counterval), 102 | .rst(rst_ppscounter) 103 | ); 104 | assign PPS_OUT2 = pps_out; 105 | assign PPS_OUT = pps_out; 106 | assign IOB_18 = GPS_PPS; 107 | 108 | wire TDC_Read; 109 | wire TDC_test; 110 | wire TDC_MOSI_test; 111 | wire [23:0] TDC_TIME1,TDC_TIME2,TDC_CLOCK_COUNT1,TDC_CALIBRATION1,TDC_CALIBRATION2; 112 | wire [119:0] TDC_DATA = {TDC_TIME1,TDC_TIME2,TDC_CLOCK_COUNT1,TDC_CALIBRATION1,TDC_CALIBRATION2}; 113 | wire TDC_dataRead; 114 | TDC7200 tdc( 115 | .rst(reset), 116 | .clk(CLOCK_BUF), 117 | .en(TDC_EN), 118 | .interrupt(TDC_Read), 119 | .CS(TDC_CS), 120 | .SCK(TDC_SCLK), 121 | .MOSI(TDC_MOSI), 122 | .MISO(TDC_MISO), 123 | .debug(TDC_test), 124 | .TIME1(TDC_TIME1), 125 | .TIME2(TDC_TIME2), 126 | .CLOCK_COUNT1(TDC_CLOCK_COUNT1), 127 | .CALIBRATION1(TDC_CALIBRATION1), 128 | .CALIBRATION2(TDC_CALIBRATION2), 129 | .dataRead(TDC_dataRead) 130 | ); 131 | 132 | wire ADC_dataRead,ADC_Debug; 133 | wire [63:0] ADC_data; 134 | wire [63:0] adc_timestamp; 135 | wire [15:0] adc_pps_tag_timestamp; 136 | wire fifo_full; 137 | ADC8681 adc( 138 | .rst(reset), 139 | .clk(CLOCK_BUF), 140 | .CS(ADC_CS), 141 | .SCK(ADC_SCLK), 142 | .MOSI(ADC_MOSI), 143 | .MISO(ADC_MISO), 144 | .debug(ADC_Debug), 145 | .ADC_data_all(ADC_data), 146 | .dataRead(ADC_dataRead), 147 | .timestamp_all(adc_timestamp), 148 | .fifo_full(fifo_full), 149 | .pps(pps_pulse), 150 | .pps_tag_timestamp(adc_pps_tag_timestamp) 151 | ); 152 | 153 | wire [31:0] ADC_data_withTimestamp_0 = {ADC_data[15:0],adc_timestamp[15:0]}; 154 | wire [31:0] ADC_data_withTimestamp_1 = {ADC_data[31:16],adc_timestamp[31:16]}; 155 | wire [31:0] ADC_data_withTimestamp_2 = {ADC_data[47:32],adc_timestamp[47:32]}; 156 | wire [31:0] ADC_data_withTimestamp_3 = {ADC_data[63:48],adc_timestamp[63:48]}; 157 | 158 | wire [127:0] ADC_data_withTimestamp_all = {ADC_data_withTimestamp_0,ADC_data_withTimestamp_1,ADC_data_withTimestamp_2,ADC_data_withTimestamp_3}; 159 | 160 | wire fifo_empty,fifo_avail; 161 | wire fifo_read,fifo_reset; 162 | wire [127:0] fifo_data_out; 163 | wire [10:0] fifo_data_count; 164 | fifo #(.data_width(128),.fifo_depth(512)) 165 | fifo_TX ( 166 | .clk(CLOCK_BUF), 167 | .rst((reset==1) & (fifo_reset==0)), 168 | 169 | // Write side => from ADC 170 | .wr_en(ADC_dataRead), 171 | .din(ADC_data_withTimestamp_all), 172 | .full(fifo_full), 173 | 174 | // Read side => SPI read 175 | .rd_en(fifo_read), 176 | .dout(fifo_data_out), 177 | .empty(fifo_empty), 178 | 179 | .avail(fifo_avail), 180 | .count(fifo_data_count) 181 | ); 182 | 183 | assign IOB_16 = fifo_avail; 184 | 185 | wire R,G,B; 186 | 187 | 188 | delayPPS delayedPPS( 189 | .clk(CLOCK_BUF), 190 | .pps_in(TDC_START), 191 | .pps_out(TDC_STOP), 192 | .rst(reset) 193 | ); 194 | delayPPS delayedPP2( 195 | .clk(CLOCK_BUF), 196 | .pps_in(TDC_STOP), 197 | .pps_out(TDC_Read), 198 | .rst(reset) 199 | ); 200 | 201 | 202 | 203 | 204 | reg [7:0] cmd_reg /* synthesis syn_preserve = 1 */; 205 | reg [7:0] status_reg; 206 | wire [7:0] mosi_byte; 207 | reg [7:0] miso_byte; 208 | wire cmd_byte; 209 | wire mosi_byte_valid; 210 | wire miso_byte_req; 211 | 212 | 213 | wire read = cmd_reg[7]; 214 | wire write = ~cmd_reg[7]; 215 | wire status_write = mosi_byte_valid && !cmd_byte && write; 216 | wire [6:0] reg_address = cmd_reg[6:0]; 217 | 218 | 219 | always @(posedge CLOCK_BUF)begin 220 | if(~reset)begin 221 | cmd_reg <= 0; 222 | end else begin 223 | if(mosi_byte_valid && cmd_byte)begin 224 | cmd_reg <= mosi_byte; 225 | end 226 | end 227 | end 228 | 229 | //READ 230 | reg miso_byte_req_d1; 231 | reg miso_byte_valid; 232 | reg [7:0] byte_cnt; 233 | 234 | always @(posedge CLOCK_BUF)begin 235 | if(~reset)begin 236 | miso_byte_valid <= 0; 237 | miso_byte_req_d1 <= 0; 238 | end else begin 239 | miso_byte_req_d1 <= miso_byte_req; 240 | miso_byte_valid <= miso_byte_req_d1; 241 | end 242 | end 243 | 244 | always @(posedge CLOCK_BUF)begin 245 | if(~reset)begin 246 | miso_byte <= 0; 247 | byte_cnt <= 0; 248 | status_reg <= 0; 249 | end else begin 250 | if(miso_byte_req_d1)begin 251 | case(reg_address) 252 | 0:miso_byte <= gpsCounterByte; 253 | 1:miso_byte <= tdcDataByte; 254 | 2:miso_byte <= fifoCount_andTagTimestamp_DataByte; 255 | 4:miso_byte <= timeDataByte; 256 | 5: begin 257 | miso_byte <= status_reg; 258 | status_reg <= 0; 259 | end 260 | endcase 261 | end 262 | else begin 263 | if(fifo_full)begin 264 | status_reg <= 1; 265 | end 266 | end 267 | if (mosi_byte_valid && ~cmd_byte) begin 268 | byte_cnt <= byte_cnt + 1; 269 | end 270 | else if(mosi_byte_valid && cmd_byte)begin 271 | byte_cnt <= 0; 272 | end 273 | end 274 | end 275 | 276 | reg [7:0] gpsCounterByte; 277 | always @ (*) begin 278 | case(byte_cnt) 279 | 0: gpsCounterByte <= GPS_counter[7:0]; 280 | 1: gpsCounterByte <= GPS_counter[15:8]; 281 | 2: gpsCounterByte <= GPS_counter[23:16]; 282 | 3: gpsCounterByte <= GPS_counter[31:24]; 283 | default:gpsCounterByte <= 0; 284 | endcase 285 | end 286 | 287 | reg [7:0] tdcDataByte; 288 | always @ (*) begin 289 | case(byte_cnt) 290 | 0: tdcDataByte <= TDC_DATA[7:0]; 291 | 1: tdcDataByte <= TDC_DATA[15:8]; 292 | 2: tdcDataByte <= TDC_DATA[23:16]; 293 | 3: tdcDataByte <= TDC_DATA[31:24]; 294 | 4: tdcDataByte <= TDC_DATA[39:32]; 295 | 5: tdcDataByte <= TDC_DATA[47:40]; 296 | 6: tdcDataByte <= TDC_DATA[55:48]; 297 | 7: tdcDataByte <= TDC_DATA[63:56]; 298 | 8: tdcDataByte <= TDC_DATA[71:64]; 299 | 9: tdcDataByte <= TDC_DATA[79:72]; 300 | 10: tdcDataByte <= TDC_DATA[87:80]; 301 | 11: tdcDataByte <= TDC_DATA[95:88]; 302 | 12: tdcDataByte <= TDC_DATA[103:96]; 303 | 13: tdcDataByte <= TDC_DATA[111:104]; 304 | 14: tdcDataByte <= TDC_DATA[119:112]; 305 | default:tdcDataByte <= 0; 306 | endcase 307 | end 308 | 309 | reg [7:0] fifoCount_andTagTimestamp_DataByte; 310 | always @ (*) begin 311 | case(byte_cnt) 312 | 0: fifoCount_andTagTimestamp_DataByte <= fifo_data_count[7:0]; 313 | 1: fifoCount_andTagTimestamp_DataByte <= fifo_data_count[10:8]; 314 | 2: fifoCount_andTagTimestamp_DataByte <= adc_pps_tag_timestamp[7:0]; 315 | 3: fifoCount_andTagTimestamp_DataByte <= adc_pps_tag_timestamp[15:8]; 316 | 4: fifoCount_andTagTimestamp_DataByte <= sec_out; 317 | 5: fifoCount_andTagTimestamp_DataByte <= min_out; 318 | 6: fifoCount_andTagTimestamp_DataByte <= hour_out; 319 | default:fifoCount_andTagTimestamp_DataByte <= 0; 320 | endcase 321 | end 322 | 323 | reg [7:0] timeDataByte; 324 | always @ (*) begin 325 | case(byte_cnt) 326 | 0: timeDataByte <= sec_out; 327 | 1: timeDataByte <= min_out; 328 | 2: timeDataByte <= hour_out; 329 | default:timeDataByte <= 0; 330 | endcase 331 | end 332 | 333 | 334 | //WRITE 335 | reg [7:0] configReg; 336 | assign align_GPS = configReg[0]; 337 | wire closeLED = configReg[1]; 338 | wire fifo_reset = configReg[2]; 339 | wire nixieHostControl = configReg[3]; 340 | wire enablePWM = configReg[4]; 341 | wire [1:0]debugMode = configReg[6:5]; 342 | 343 | wire config_set = mosi_byte_valid && !cmd_byte && write && (reg_address == 0); 344 | wire config_clr = mosi_byte_valid && !cmd_byte && write && (reg_address == 14); 345 | 346 | wire second_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 1); 347 | wire minute_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 2); 348 | wire hour_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 3); 349 | 350 | wire nixie12_digit_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 4); 351 | wire nixie34_digit_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 5); 352 | wire nixie56_digit_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 6); 353 | wire nixie78_digit_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 7); 354 | 355 | wire nixie1234_dp_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 8); 356 | wire nixie5678_dp_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 9); 357 | 358 | wire PWM_Low_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 10); 359 | wire PWM_High_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 11); 360 | 361 | wire PWM_Div_Low_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 12); 362 | wire PWM_Div_High_write = mosi_byte_valid && !cmd_byte && write && (reg_address == 13); 363 | 364 | 365 | reg rtc_write; 366 | reg [7:0] second; 367 | reg [7:0] minute; 368 | reg [7:0] hour; 369 | 370 | reg nixie_write; 371 | reg [7:0] nixie12_digit; 372 | reg [7:0] nixie34_digit; 373 | reg [7:0] nixie56_digit; 374 | reg [7:0] nixie78_digit; 375 | 376 | reg [7:0] nixie1234_dp; 377 | reg [7:0] nixie5678_dp; 378 | 379 | reg pwm_write; 380 | reg [7:0] PWM_Low_reg; 381 | reg [7:0] PWM_High_reg; 382 | 383 | reg pwm_div_write; 384 | reg [7:0] PWM_Div_Low_reg; 385 | reg [7:0] PWM_Div_High_reg; 386 | 387 | always @(posedge CLOCK_BUF)begin 388 | if(~reset)begin 389 | configReg <= 0; 390 | end else begin 391 | if(fifo_reset) configReg[2] <= 0; 392 | if(config_set)begin 393 | configReg <= configReg | mosi_byte; 394 | end 395 | if(config_clr)begin 396 | configReg <= configReg & ~mosi_byte; 397 | end 398 | if(second_write)begin 399 | second <= mosi_byte; 400 | end 401 | if(minute_write)begin 402 | minute <= mosi_byte; 403 | end 404 | if(hour_write)begin 405 | hour <= mosi_byte; 406 | end 407 | 408 | if(nixie12_digit_write)begin 409 | nixie12_digit <= mosi_byte; 410 | end 411 | if(nixie34_digit_write)begin 412 | nixie34_digit <= mosi_byte; 413 | end 414 | if(nixie56_digit_write)begin 415 | nixie56_digit <= mosi_byte; 416 | end 417 | if(nixie78_digit_write)begin 418 | nixie78_digit <= mosi_byte; 419 | end 420 | if(nixie1234_dp_write)begin 421 | nixie1234_dp <= mosi_byte; 422 | end 423 | if(nixie5678_dp_write)begin 424 | nixie5678_dp <= mosi_byte; 425 | end 426 | 427 | if(PWM_Low_write)begin 428 | PWM_Low_reg <= mosi_byte; 429 | end 430 | if(PWM_High_write)begin 431 | PWM_High_reg <= mosi_byte; 432 | end 433 | if(PWM_Div_Low_write)begin 434 | PWM_Div_Low_reg <= mosi_byte; 435 | end 436 | if(PWM_Div_High_write)begin 437 | PWM_Div_High_reg <= mosi_byte; 438 | end 439 | 440 | end 441 | if(hour_write | minute_write | second_write) begin 442 | rtc_write <= 1; 443 | end 444 | else begin 445 | rtc_write <= 0; 446 | end 447 | if(nixie78_digit_write | nixie5678_dp_write) begin 448 | nixie_write <= 1; 449 | end 450 | else begin 451 | nixie_write <= 0; 452 | end 453 | 454 | if(PWM_High_write) begin 455 | pwm_write <= 1; 456 | end 457 | else begin 458 | pwm_write <= 0; 459 | end 460 | if(PWM_Div_High_write) begin 461 | pwm_div_write <= 1; 462 | end 463 | else begin 464 | pwm_div_write <= 0; 465 | end 466 | end 467 | 468 | 469 | wire MISO_CONF; 470 | 471 | spi_slave rpi_spi_dev( 472 | .i_sys_clk(CLOCK_BUF), //System clock input 473 | .i_sys_rst(~reset), //Active high reset input 474 | 475 | .miso_byte(miso_byte), 476 | .miso_byte_valid(miso_byte_valid), 477 | .miso_byte_req(miso_byte_req), 478 | 479 | .mosi_byte(mosi_byte), 480 | .mosi_byte_valid(mosi_byte_valid), 481 | .cmd_byte(cmd_byte), 482 | 483 | //SPI port 484 | .o_miso(MISO_CONF), 485 | .i_mosi(MOSI), 486 | .i_csn(CS), 487 | .i_sclk(SCK) 488 | ); 489 | 490 | 491 | wire MISO_ADC,CS2; 492 | wire CLKHF; 493 | oschf osc2( 494 | .clkhfpu(1'b1), 495 | .clkhfen(reset), 496 | .clkhf(CLKHF) 497 | ); 498 | 499 | reg fifo_read_req; 500 | wire SCK_ADC; 501 | 502 | wire adc_miso_byte_valid,adc_mosi_byte_valid,adc_miso_byte_req; 503 | wire adc_cmd_byte; 504 | 505 | //CMD 506 | reg [7:0] adc_cmd_reg /* synthesis syn_keep = 1 */; 507 | wire [7:0] adc_mosi_byte; 508 | reg [7:0] adc_miso_byte; 509 | always @(posedge CLKHF)begin 510 | if(~reset)begin 511 | adc_cmd_reg <= 0; 512 | end else begin 513 | if(adc_mosi_byte_valid && adc_cmd_byte)begin 514 | adc_cmd_reg <= adc_mosi_byte; 515 | end 516 | end 517 | end 518 | 519 | //READ 520 | reg adc_miso_byte_req_d1; 521 | reg adc_miso_byte_valid; 522 | reg [7:0] adc_byte_cnt; 523 | 524 | always @(posedge CLKHF)begin 525 | if(~reset)begin 526 | adc_miso_byte_valid <= 0; 527 | adc_miso_byte_req_d1 <= 0; 528 | end else begin 529 | adc_miso_byte_req_d1 <= adc_miso_byte_req; 530 | adc_miso_byte_valid <= adc_miso_byte_req_d1; 531 | end 532 | end 533 | 534 | always @(posedge CLKHF)begin 535 | if(~reset)begin 536 | adc_miso_byte <= 0; 537 | adc_byte_cnt <= 0; 538 | end else begin 539 | if(adc_miso_byte_req_d1)begin 540 | case(adc_cmd_reg) 541 | 0:adc_miso_byte <= adc_adcDataByte; 542 | 1:adc_miso_byte <= adc_fifoCount_andTagTimestamp_DataByte; 543 | default:adc_miso_byte <= 0; 544 | endcase 545 | end 546 | if (adc_miso_byte_req_d1 && ~adc_cmd_byte) begin 547 | adc_byte_cnt <= adc_byte_cnt + 1; 548 | end 549 | if(adc_mosi_byte_valid && adc_cmd_byte)begin 550 | adc_byte_cnt <= 0; 551 | end 552 | else if (adc_byte_cnt == 8'd16) begin 553 | fifo_read_req <= 1; 554 | adc_byte_cnt <= 0; 555 | end 556 | else begin 557 | fifo_read_req <= 0; 558 | end 559 | end 560 | end 561 | 562 | reg [7:0] adc_fifoCount_andTagTimestamp_DataByte; 563 | always @ (*) begin 564 | case(adc_byte_cnt) 565 | 0: adc_fifoCount_andTagTimestamp_DataByte <= fifo_data_count[7:0]; 566 | 1: adc_fifoCount_andTagTimestamp_DataByte <= fifo_data_count[10:8]; 567 | default:adc_fifoCount_andTagTimestamp_DataByte <= 0; 568 | endcase 569 | end 570 | 571 | reg [7:0] adc_adcDataByte; 572 | always @ (*) begin 573 | case(adc_byte_cnt) 574 | 0: adc_adcDataByte <= fifo_data_out[7:0]; 575 | 1: adc_adcDataByte <= fifo_data_out[15:8]; 576 | 2: adc_adcDataByte <= fifo_data_out[23:16]; 577 | 3: adc_adcDataByte <= fifo_data_out[31:24]; 578 | 4: adc_adcDataByte <= fifo_data_out[39:32]; 579 | 5: adc_adcDataByte <= fifo_data_out[47:40]; 580 | 6: adc_adcDataByte <= fifo_data_out[55:48]; 581 | 7: adc_adcDataByte <= fifo_data_out[63:56]; 582 | 8: adc_adcDataByte <= fifo_data_out[71:64]; 583 | 9: adc_adcDataByte <= fifo_data_out[79:72]; 584 | 10: adc_adcDataByte <= fifo_data_out[87:80]; 585 | 11: adc_adcDataByte <= fifo_data_out[95:88]; 586 | 12: adc_adcDataByte <= fifo_data_out[103:96]; 587 | 13: adc_adcDataByte <= fifo_data_out[111:104]; 588 | 14: adc_adcDataByte <= fifo_data_out[119:112]; 589 | 15: adc_adcDataByte <= fifo_data_out[127:120]; 590 | default:adc_adcDataByte <= 0; 591 | endcase 592 | end 593 | 594 | 595 | spi_slave2 rpi_adc_dev( 596 | .i_sys_clk(CLKHF), //System clock input 597 | .i_sys_rst(~reset), //Active high reset input 598 | 599 | .miso_byte(adc_miso_byte), 600 | .miso_byte_valid(adc_miso_byte_valid), 601 | .miso_byte_req(adc_miso_byte_req), 602 | 603 | .mosi_byte(adc_mosi_byte), 604 | .mosi_byte_valid(adc_mosi_byte_valid), 605 | .cmd_byte(adc_cmd_byte), 606 | 607 | //SPI port 608 | .o_miso(MISO_ADC), 609 | .i_mosi(MOSI), 610 | .i_csn(IOB_20), 611 | .i_sclk(SCK) 612 | ); 613 | 614 | 615 | localparam DISABLE_DEBUG = 2'b00; 616 | localparam PPS_DEBUG = 2'b01; 617 | localparam SPI_DEBUG = 2'b10; 618 | localparam ADC_DEBUG = 2'b11; 619 | 620 | reg debug_1,debug_2,debug_3,debug_4,debug_5; 621 | always @(*) begin 622 | case(debugMode) 623 | DISABLE_DEBUG: begin 624 | debug_1 <= 0; 625 | debug_2 <= 0; 626 | debug_3 <= 0; 627 | debug_4 <= 0; 628 | debug_5 <= 0; 629 | end 630 | PPS_DEBUG: begin 631 | debug_1 <= GPS_PPS; 632 | debug_2 <= pps_out; 633 | debug_3 <= 0; 634 | debug_4 <= 0; 635 | debug_5 <= 0; 636 | end 637 | SPI_DEBUG: begin 638 | debug_1 <= MISO_CONF; 639 | debug_2 <= MOSI; 640 | debug_3 <= CS; 641 | debug_4 <= SCK; 642 | debug_5 <= 0; 643 | end 644 | ADC_DEBUG: begin 645 | debug_1 <= MISO_ADC; 646 | debug_2 <= MOSI; 647 | debug_3 <= IOB_20; 648 | debug_4 <= SCK; 649 | debug_5 <= 0; 650 | end 651 | default: begin 652 | debug_1 <= 0; 653 | debug_2 <= 0; 654 | debug_3 <= 0; 655 | debug_4 <= 0; 656 | debug_5 <= 0; 657 | end 658 | endcase 659 | end 660 | 661 | assign IOB_2 = debug_1; 662 | assign IOB_0 = debug_2; 663 | assign IOB_3 = debug_3; 664 | assign IOB_49 = debug_4; 665 | assign IOB_51 = debug_5; 666 | 667 | reg fifo_read_hf,fifo_read_lf_1,fifo_read_lf_2,fifo_read_lf_3; 668 | 669 | always @(posedge CLKHF) begin 670 | if(fifo_read_req) begin 671 | fifo_read_hf <= ~fifo_read_hf; 672 | end 673 | end 674 | always @(posedge CLOCK_BUF) begin 675 | fifo_read_lf_1 <= fifo_read_hf; 676 | fifo_read_lf_2 <= fifo_read_lf_1; 677 | fifo_read_lf_3 <= fifo_read_lf_2; 678 | end 679 | assign fifo_read = fifo_read_lf_2 ^ fifo_read_lf_3; 680 | 681 | assign MISO = CS ? MISO_ADC : MISO_CONF; 682 | 683 | 684 | //GPS_PPS Measurement 685 | wire [31:0] GPS_counter; 686 | wire GPS_update; 687 | CounterModule ppscounter( 688 | .inputsig(TDC_START), 689 | .clk(CLOCK_BUF), 690 | .rst(reset), 691 | .falling_rising(1'b0), 692 | .counter(GPS_counter), 693 | .trigger(GPS_update) 694 | ); 695 | 696 | wire [31:0] RTC_display_digit,RTC_display_digitPoint; 697 | wire [5:0] sec_out,min_out,hour_out; 698 | RTC rtc( 699 | .clk(CLOCK_BUF), 700 | .rst(reset), 701 | .pps(pps_pulse), 702 | .sec_in(second), 703 | .min_in(minute), 704 | .hour_in(hour), 705 | 706 | .sec_out(sec_out), 707 | .min_out(min_out), 708 | .hour_out(hour_out), 709 | 710 | .display_time(RTC_display_digit), 711 | .display_digit(RTC_display_digitPoint), 712 | .write_data(rtc_write) 713 | ); 714 | 715 | 716 | wire updateNixie = nixieHostControl? nixie_write : pps_pulse; 717 | wire [31:0] NixieDigit = nixieHostControl? {nixie12_digit,nixie34_digit,nixie56_digit,nixie78_digit} : RTC_display_digit; 718 | wire [31:0] NixieDigitPoint = nixieHostControl? {nixie1234_dp,nixie5678_dp} : RTC_display_digitPoint; 719 | NixieCounter nixie( 720 | .clk(CLOCK_BUF), 721 | .rst(reset), 722 | .NixieBCD(NixieDigit), 723 | .digitpoint(NixieDigitPoint), 724 | .NIXIE_LE(NIXIE_LE), 725 | .NIXIE_CLK(NIXIE_CLK), 726 | .NIXIE_DIN(NIXIE_DIN), 727 | .pps(updateNixie), 728 | .Done() 729 | ); 730 | 731 | wire nixie_pwm; 732 | pdm pdmdata( 733 | .clk(CLOCK_BUF), 734 | .PWM_in({PWM_High_reg,PWM_Low_reg}), 735 | .divider({PWM_Div_High_reg,PWM_Div_Low_reg}), 736 | .PWM_out(nixie_pwm), 737 | .pwm_write(pwm_write), 738 | .pwm_div_write(pwm_div_write), 739 | .rst(reset) 740 | ); 741 | 742 | 743 | assign NIXIE_BL = enablePWM ? nixie_pwm : 1'b1; 744 | 745 | assign R = ~fifo_full | closeLED; 746 | assign G = ~GPS_PPS | closeLED; 747 | assign B = ~TDC_STOP | closeLED; 748 | SB_IO_OD #( 749 | .PIN_TYPE(6'b011001), 750 | .NEG_TRIGGER(1'b0) 751 | ) pin_out_driverB ( 752 | .PACKAGEPIN(pin_ledB), 753 | .DOUT0(B) 754 | ); 755 | SB_IO_OD #( 756 | .PIN_TYPE(6'b011001), 757 | .NEG_TRIGGER(1'b0) 758 | ) pin_out_driverR ( 759 | .PACKAGEPIN(pin_ledR), 760 | .DOUT0(R) 761 | ); 762 | SB_IO_OD #( 763 | .PIN_TYPE(6'b011001), 764 | .NEG_TRIGGER(1'b0) 765 | ) pin_out_driverG ( 766 | .PACKAGEPIN(pin_ledG), 767 | .DOUT0(G) 768 | ); 769 | 770 | endmodule 771 | 772 | 773 | module oschf ( 774 | input clkhfpu, 775 | input clkhfen, 776 | output clkhf 777 | ); 778 | 779 | SB_HFOSC #( 780 | .CLKHF_DIV("0b00") 781 | ) hfosc ( 782 | .CLKHFPU(clkhfpu), 783 | .CLKHFEN(clkhfen), 784 | .CLKHF(clkhf) 785 | ); 786 | 787 | endmodule --------------------------------------------------------------------------------