├── libtungsten ├── .gitignore ├── openocd.cfg ├── usbcom │ ├── __pycache__ │ │ └── usbcom.cpython-36.pyc │ ├── Makefile │ ├── usbcom_write.cpp │ ├── USBCom.h │ ├── usbcom_dump.cpp │ ├── usbcom_gui.py │ ├── usbcom.py │ └── USBCom.cpp ├── ld_scripts │ ├── bootloader.ld │ ├── usercode_ls2x.ld │ ├── usercode_ls4x.ld │ ├── usercode_ls8x.ld │ ├── usercode_bootloader_ls2x.ld │ ├── usercode_bootloader_ls4x.ld │ ├── usercode_bootloader_ls8x.ld │ └── common.ld ├── sam4l │ ├── utils.h │ ├── trng.h │ ├── interrupt_priorities.cpp │ ├── error.h │ ├── gloc.h │ ├── error.cpp │ ├── dac.h │ ├── trng.cpp │ ├── eic.h │ ├── wdt.h │ ├── ast.h │ ├── adc.h │ ├── startup.cpp │ ├── bpm.h │ ├── bscif.h │ ├── dma.h │ ├── flash.h │ ├── spi.h │ ├── gloc.cpp │ ├── bscif.cpp │ ├── usart.h │ ├── ast.cpp │ ├── flash.cpp │ ├── dac.cpp │ ├── eic.cpp │ ├── adc.cpp │ ├── pins_sam4l_48.cpp │ ├── bpm.cpp │ ├── scif.h │ └── i2c.h ├── template │ ├── myproject.cpp.template │ └── Makefile.template ├── bootloader │ ├── Makefile │ └── bootloader_config.h ├── utils │ ├── Servo.h │ ├── USBCom.h │ ├── Servo.cpp │ ├── RingBuffer.h │ └── RingBuffer.cpp └── carbide │ ├── carbide.h │ └── carbide.cpp ├── drivers ├── lora │ ├── docs │ │ └── RFM95_96_97_98W.pdf │ └── lora.h └── oled_ssd1306 │ ├── docs │ └── SSD1306.pdf │ ├── font.h │ └── oled.h ├── icons ├── settings.pbm ├── focus.pbm ├── input.pbm ├── delay.pbm ├── intvl.pbm ├── advanced.pbm ├── trigger.pbm ├── silica.pbm ├── bitmap_convert.py └── silica_64.pbm ├── silver.h ├── README.md ├── sync_usb.h ├── Makefile ├── sync.h ├── context.h ├── pins.h ├── gui.h ├── sync.cpp ├── context.cpp └── sync_usb.cpp /libtungsten/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.elf 3 | *.hex 4 | codeuploader 5 | -------------------------------------------------------------------------------- /drivers/lora/docs/RFM95_96_97_98W.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foalyy/silver-firmware/HEAD/drivers/lora/docs/RFM95_96_97_98W.pdf -------------------------------------------------------------------------------- /drivers/oled_ssd1306/docs/SSD1306.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foalyy/silver-firmware/HEAD/drivers/oled_ssd1306/docs/SSD1306.pdf -------------------------------------------------------------------------------- /icons/settings.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 6 8 4 | 010010010010110011110011011110001100001100001100 -------------------------------------------------------------------------------- /libtungsten/openocd.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/cmsis-dap.cfg] 2 | set CHIPNAME ATSAM4LS8B 3 | source [find target/at91sam4lXX.cfg] -------------------------------------------------------------------------------- /icons/focus.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 7 8 4 | 01111101000001101110110100011011001101000110000010111110 -------------------------------------------------------------------------------- /icons/input.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 7 8 4 | 00000000010001000100100001011111111000010100010010010001 -------------------------------------------------------------------------------- /icons/delay.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 8 8 4 | 0011110001000010100100011001000110011101100000010100001000111100 -------------------------------------------------------------------------------- /icons/intvl.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 8 8 4 | 0000000000001111000000010011110100000100111101001001000011110000 -------------------------------------------------------------------------------- /icons/advanced.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 8 8 4 | 0000000000000010000001110011101001111100011011000111110000111000 -------------------------------------------------------------------------------- /icons/trigger.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 8 8 4 | 0011110001000010100000011001100110011001100000010100001000111100 -------------------------------------------------------------------------------- /libtungsten/usbcom/__pycache__/usbcom.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Foalyy/silver-firmware/HEAD/libtungsten/usbcom/__pycache__/usbcom.cpython-36.pyc -------------------------------------------------------------------------------- /libtungsten/ld_scripts/bootloader.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x4000 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_ls2x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x20000 /* 128K */ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_ls4x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x40000 /* 256K */ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_ls8x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 512K */ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 /* 64K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/sam4l/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H_ 2 | #define _UTILS_H_ 3 | 4 | inline int min(int a, int b) { return (a < b ? a : b); }; 5 | inline int max(int a, int b) { return (a > b ? a : b); }; 6 | 7 | #endif -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_bootloader_ls2x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x4000, LENGTH = 0x1C000 /* 128K (0x20000) minus bootloader*/ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_bootloader_ls4x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x4000, LENGTH = 0x3C000 /* 256K (0x40000) minus bootloader*/ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /libtungsten/ld_scripts/usercode_bootloader_ls8x.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x4000, LENGTH = 0x7C000 /* 512K (0x80000) minus bootloader*/ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 /* 64K */ 5 | } 6 | 7 | INCLUDE common.ld -------------------------------------------------------------------------------- /silver.h: -------------------------------------------------------------------------------- 1 | #ifndef _SILVER_H_ 2 | #define _SILVER_H_ 3 | 4 | 5 | 6 | void warningHandler(Error::Module module=Error::Module::CUSTOM, int userModule=0, Error::Code code=0); 7 | void criticalHandler(Error::Module module=Error::Module::CUSTOM, int userModule=0, Error::Code code=0); 8 | 9 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Silver 2 | 3 | Silver is an open-source project aiming at making a long-range and fully-featured camera remote control. 4 | 5 | See https://silica.io/tag/silver/ and https://hackaday.io/project/167218-silver for more information about this project. 6 | 7 | See https://github.com/Foalyy/silver-kicad for the Kicad project. 8 | 9 | ![silver](https://silica.io/wp-content/uploads/2019/08/DSC_1946.jpg) 10 | -------------------------------------------------------------------------------- /libtungsten/usbcom/Makefile: -------------------------------------------------------------------------------- 1 | ## Settings 2 | 3 | CXX=g++ 4 | CXXFLAGS=-std=c++11 -Wall -g 5 | LFLAGS=-lusb-1.0 6 | OBJS=USBCom.o 7 | 8 | 9 | ## RULES 10 | 11 | .PHONY: clean 12 | 13 | all: usbcom_dump usbcom_write 14 | 15 | usbcom_dump: usbcom_dump.cpp $(OBJS) 16 | $(CXX) $(CXXFLAGS) $^ -o $@ $(LFLAGS) 17 | 18 | usbcom_write: usbcom_write.cpp $(OBJS) 19 | $(CXX) $(CXXFLAGS) $^ -o $@ $(LFLAGS) 20 | 21 | %.o: %.cpp %.h 22 | $(CXX) $(CXXFLAGS) -c $< -o $@ $(LFLAGS) 23 | 24 | clean: 25 | rm -f usbcom_dump usbcom_write *.o 26 | -------------------------------------------------------------------------------- /libtungsten/template/myproject.cpp.template: -------------------------------------------------------------------------------- 1 | #include 2 | // Include library headers here to add modules in your project, e.g. 3 | // #include 4 | // For modules that are not compiled by default, don't forget to also add them 5 | // in the MODULE parameter in your Makefile 6 | 7 | int main() { 8 | // Initialize the microcontroller, leds and button 9 | Carbide::init(); 10 | 11 | // ... more initialization stuff ... 12 | 13 | // Running loop 14 | while (1) { 15 | // Your program goes there! 16 | } 17 | } -------------------------------------------------------------------------------- /libtungsten/bootloader/Makefile: -------------------------------------------------------------------------------- 1 | ## libtungsten project compilation config 2 | # Remember to do 'make clean' whenever you change anything in this Makefile 3 | 4 | NAME=bootloader 5 | #DEBUG=true 6 | 7 | # Available modules : adc dac eic gloc i2c spi tc trng usart wdt. 8 | # Some modules such as gpio and flash are already compiled by default 9 | # and must not be added here. 10 | MODULES=usart 11 | 12 | # Path to the toolchain. If the tools (such as arm-none-eabi-g++) are 13 | # not in your default $PATH, you MUST define their location here. 14 | # (don't forget the trailing slash) 15 | TOOLCHAIN_PATH=/home/foaly/Software/gcc-arm-none-eabi/bin/ 16 | 17 | # Include the main lib makefile 18 | ROOTDIR=../.. 19 | LDSCRIPTNAME=bootloader.ld 20 | ADD_CXXFLAGS=-fno-exceptions 21 | include ../Makefile 22 | -------------------------------------------------------------------------------- /sync_usb.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYNC_USB_H_ 2 | #define _SYNC_USB_H_ 3 | 4 | #include 5 | #include "context.h" 6 | 7 | namespace SyncUSB { 8 | 9 | const uint16_t USB_VENDOR_ID = USB::DEFAULT_VENDOR_ID; 10 | const uint16_t USB_PRODUCT_ID = 0xcbd0; 11 | const char STR_MANUFACTURER[] = "Silica"; 12 | const char STR_PRODUCT[] = "Silver"; 13 | const char STR_SERIALNUMBER[] = "v1"; 14 | 15 | const uint8_t REQUEST_START_BOOTLOADER = 0x00; 16 | 17 | void init(); 18 | bool commandAvailable(); 19 | uint8_t getCommand(); 20 | int getPayload(uint8_t* buffer); 21 | void send(uint8_t command, uint8_t* payload=nullptr, int payloadSize=0); 22 | bool isConnected(); 23 | void usbConnectedHandler(); 24 | void usbDisconnectedHandler(); 25 | int usbControlHandler(USB::SetupPacket &lastSetupPacket, uint8_t* data, int size); 26 | 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## CONFIG 2 | 3 | NAME=silver 4 | 5 | BOOTLOADER=false 6 | DEBUG=true 7 | #CARBIDE=true 8 | PACKAGE=64 9 | 10 | # Available modules : adc dac eic gloc i2c spi tc trng usart wdt 11 | # If not specified, all modules will be compiled 12 | MODULES=spi adc 13 | 14 | # Available utils modules : RingBuffer 15 | # If not specified, all utils modules will be compiled 16 | UTILS_MODULES= 17 | 18 | USER_MODULES=\ 19 | gui \ 20 | sync \ 21 | sync_usb \ 22 | context \ 23 | drivers/oled_ssd1306/oled \ 24 | drivers/oled_ssd1306/font_small \ 25 | drivers/oled_ssd1306/font_medium \ 26 | drivers/oled_ssd1306/font_large \ 27 | drivers/lora/lora 28 | 29 | TOOLCHAIN_PATH=/home/foaly/Software/gcc-arm-none-eabi/bin/ 30 | 31 | # Include the main lib makefile 32 | include libtungsten/Makefile 33 | 34 | # Custom rules 35 | clean: clean-all 36 | rm -f drivers/*.o 37 | rm -f drivers/lora/*.o 38 | rm -f drivers/oled_ssd1306/*.o 39 | -------------------------------------------------------------------------------- /libtungsten/template/Makefile.template: -------------------------------------------------------------------------------- 1 | ## libtungsten project compilation config 2 | # Remember to do 'make clean' whenever you change anything in this Makefile 3 | 4 | NAME=myproject 5 | 6 | #BOOTLOADER=true 7 | DEBUG=true 8 | CARBIDE=true 9 | 10 | # Available modules : adc dac eic gloc i2c spi tc trng usart 11 | # Some modules such as gpio and flash are already compiled by default 12 | # and must not be added here. 13 | MODULES= 14 | 15 | # Available utils modules : RingBuffer Servo 16 | UTILS_MODULES= 17 | 18 | # User-defined modules to compile with your project 19 | # Example : 20 | # USER_MODULES=\ 21 | # leds 22 | # drivers/SDCard \ 23 | # drivers/GPS 24 | USER_MODULES= 25 | 26 | # Path to the toolchain. If the tools (such as arm-none-eabi-g++) are 27 | # not in your default $PATH, you MUST define their location here. 28 | # (don't forget the trailing slash) 29 | #TOOLCHAIN_PATH=/path/to/arm-none-eabi/bin/ 30 | 31 | # Include the main lib makefile 32 | include libtungsten/Makefile 33 | -------------------------------------------------------------------------------- /sync.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYNC_H_ 2 | #define _SYNC_H_ 3 | 4 | #include 5 | 6 | namespace Sync { 7 | 8 | const uint32_t LORA_FREQUENCY = 869350000L; // 868.25MHz 9 | 10 | const int N_CHANNELS = 255; 11 | const uint8_t SYNC_PREAMBLE = 0x42; 12 | 13 | const int HEADER_SIZE = 3; 14 | const uint8_t HEADER_PREAMBLE = 0; 15 | const uint8_t HEADER_CHANNEL = 1; 16 | const uint8_t HEADER_COMMAND = 2; 17 | const int MAX_PAYLOAD_SIZE = 10; 18 | 19 | const uint8_t CMD_GET_GUI_STATE = 0x80; 20 | const uint8_t CMD_GET_GUI_UPDATE = 0x81; 21 | const uint8_t CMD_FOCUS = 0x90; 22 | const uint8_t CMD_FOCUS_HOLD = 0x91; 23 | const uint8_t CMD_FOCUS_RELEASE = 0x92; 24 | const uint8_t CMD_TRIGGER = 0x93; 25 | const uint8_t CMD_TRIGGER_NO_DELAY = 0x94; 26 | const uint8_t CMD_TRIGGER_HOLD = 0x95; 27 | const uint8_t CMD_TRIGGER_RELEASE = 0x96; 28 | 29 | 30 | bool init(); 31 | bool commandAvailable(); 32 | uint8_t getCommand(); 33 | int getRSSI(); 34 | int getPayload(uint8_t* buffer); 35 | void send(uint8_t command, uint8_t* payload=nullptr, int payloadSize=0); 36 | 37 | } 38 | 39 | #endif -------------------------------------------------------------------------------- /icons/silica.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 32 32 4 | 0000000000000000000000000000000000000000000000000000000000000000000000 5 | 0000000000000000000000000000000000000000000000000000000000000011111111 6 | 0000000001100000000000110000000010000000110110000000001110000000010000 7 | 0011100100000000111100000000110001111000100000000111100000000010011110 8 | 0010000000011111000000000101111000100000000111111000000000111110001000 9 | 0000011111111000000001111000100000000111111111000000000110000100000001 10 | 1111111110000000001100010000000001111111110000000001000100000000001111 11 | 1111110000000011010000000000011111111110000000001100000000000001111111 12 | 1100000000011000000000000011111111100000000010000000000000011111111110 13 | 0000001000000000000001000011111111000010000000000001100000000000001000 14 | 1000000000001000000000000000010001000000000011111100000000000010010000 15 | 0000000111111111111111111101000000000000111111111111111111110000000000 16 | 0001111111111111111110000000000000001111111111111000000000000000000000 17 | 0000000000000000000000000000000000000000000000000000000000000000000000 18 | 00000000000000000000000000000000000000000000 -------------------------------------------------------------------------------- /libtungsten/sam4l/trng.h: -------------------------------------------------------------------------------- 1 | #ifndef _TRNG_H_ 2 | #define _TRNG_H_ 3 | 4 | #include 5 | 6 | // True Random Number Generator 7 | // This module provides 32-bit highly random numbers 8 | // based on specified hardware. 9 | namespace TRNG { 10 | 11 | // Peripheral memory space base address 12 | const uint32_t BASE = 0x40068000; 13 | 14 | // Registers addresses 15 | const uint32_t OFFSET_CR = 0x00; // Control Register 16 | const uint32_t OFFSET_IER = 0x10; // Interrupt Enable Register 17 | const uint32_t OFFSET_IDR = 0x14; // Interrupt Disable Register 18 | const uint32_t OFFSET_IMR = 0x18; // Interrupt Mask Register 19 | const uint32_t OFFSET_ISR = 0x1C; // Interrupt Status Register 20 | const uint32_t OFFSET_ODATA = 0x50; // Output Data Register 21 | 22 | // Constants 23 | const uint32_t CR_ENABLE = 0; 24 | const uint32_t CR_KEY = 0x524E47 << 8; 25 | const uint32_t ISR_DATRDY = 0; 26 | 27 | 28 | void enable(); 29 | bool available(); 30 | uint32_t get(); 31 | void enableInterrupt(void (*handler)(uint32_t)); 32 | void disableInterrupt(); 33 | 34 | } 35 | 36 | 37 | #endif -------------------------------------------------------------------------------- /libtungsten/usbcom/usbcom_write.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "USBCom.h" 5 | 6 | 7 | // Simple program to receive data using the USBCom class and print it 8 | // on the standard output. 9 | 10 | 11 | // Handler called to stop listening when Ctrl+C is pressed (SIGINT is sent) 12 | volatile bool _exit = false; 13 | void sigIntHandler(int signum) { 14 | _exit = true; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | USBCom usbcom; 19 | usbcom.init(); 20 | 21 | // Register the SIGINT handler 22 | struct sigaction sigIntAction; 23 | sigIntAction.sa_handler = sigIntHandler; 24 | sigemptyset(&sigIntAction.sa_mask); 25 | sigIntAction.sa_flags = 0; 26 | sigaction(SIGINT, &sigIntAction, NULL); 27 | 28 | // Read and print data until _exit is set 29 | while (!_exit) { 30 | // Read a string on stdin 31 | std::string str; 32 | std::cin >> str; 33 | str += "\n"; 34 | 35 | // Send to USBCom 36 | usbcom.write((const uint8_t*)str.c_str(), str.size()); 37 | } 38 | 39 | // Close the USB connection 40 | usbcom.close(); 41 | } 42 | -------------------------------------------------------------------------------- /libtungsten/usbcom/USBCom.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_COM_H_ 2 | #define _USB_COM_H_ 3 | 4 | #include 5 | #include 6 | 7 | class USBCom { 8 | private: 9 | 10 | const uint16_t DEFAULT_USB_VENDOR_ID = 0x03eb; 11 | const uint16_t DEFAULT_USB_PRODUCT_ID = 0xcabd; 12 | const uint16_t DEFAULT_INTERFACE = 0; 13 | 14 | enum class Direction { 15 | OUTPUT = 0, 16 | INPUT = 1, 17 | }; 18 | 19 | libusb_device_handle* _handle = nullptr; 20 | 21 | int sendRequestInternal(uint8_t request, uint16_t value=0, uint16_t index=0, Direction direction=Direction::OUTPUT, uint8_t* buffer=nullptr, uint16_t length=0, int timeout=0); 22 | int findDevice(uint16_t vid, uint16_t pid); 23 | void printLibUSBError(std::string message, int r); 24 | 25 | public: 26 | int init(); 27 | void close(); 28 | int read(uint8_t* buffer, int maxLength, int timeout=0); 29 | int write(const uint8_t* buffer, int length, int timeout=0); 30 | int sendRequest(uint8_t request, uint16_t value=0, uint16_t index=0, Direction direction=Direction::OUTPUT, uint8_t* buffer=nullptr, uint16_t length=0, int timeout=0); 31 | 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /libtungsten/utils/Servo.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERVO_H_ 2 | #define _SERVO_H_ 3 | 4 | #include 5 | #include 6 | 7 | // This class is a shallow helper to use a TC channel as a PWM generator to control a servomotor 8 | class Servo { 9 | private: 10 | TC::Channel _tcChannel; 11 | GPIO::Pin _pin; 12 | unsigned int _period; 13 | unsigned int _highTime0; 14 | unsigned int _highTime100; 15 | unsigned int _percent; 16 | bool _disabled; 17 | 18 | static const unsigned int DEFAULT_PERIOD = 10000; 19 | static const unsigned int DEFAULT_HIGH_TIME_0 = 1000; 20 | static const unsigned int DEFAULT_HIGH_TIME_100 = 2000; 21 | 22 | public: 23 | // Constructor : must specify the underlying TC channel to use 24 | Servo(TC::Channel tcChannel, GPIO::Pin pin={GPIO::Port::A, 0xFF}); 25 | 26 | // Set the servo position in percent 27 | // This will translate to differant angles according to the exact servo angular range 28 | void set(unsigned int percent); 29 | 30 | void disable(); 31 | 32 | // Customize the PWM timings 33 | // Passing no argument resets the default values 34 | void setPWMTimings(unsigned int highTime0=DEFAULT_HIGH_TIME_0, unsigned int highTime100=DEFAULT_HIGH_TIME_100, unsigned int period=DEFAULT_PERIOD); 35 | 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /libtungsten/usbcom/usbcom_dump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "USBCom.h" 5 | 6 | 7 | // Simple program to receive data using the USBCom class and print it 8 | // on the standard output. 9 | 10 | 11 | // Handler called to stop listening when Ctrl+C is pressed (SIGINT is sent) 12 | volatile bool _exit = false; 13 | void sigIntHandler(int signum) { 14 | _exit = true; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | USBCom usbcom; 19 | usbcom.init(); 20 | 21 | // Register the SIGINT handler 22 | struct sigaction sigIntAction; 23 | sigIntAction.sa_handler = sigIntHandler; 24 | sigemptyset(&sigIntAction.sa_mask); 25 | sigIntAction.sa_flags = 0; 26 | sigaction(SIGINT, &sigIntAction, NULL); 27 | 28 | // Read and print data until _exit is set 29 | const int BUFFER_SIZE = 64; 30 | uint8_t buffer[BUFFER_SIZE]; 31 | int transferredLength = 0; 32 | while (!_exit) { 33 | // Read 34 | transferredLength = usbcom.read(buffer, BUFFER_SIZE); 35 | 36 | // Print 37 | for (int i = 0; i < transferredLength; i++) { 38 | std::cout << (char)buffer[i]; 39 | } 40 | std::cout << std::flush; 41 | } 42 | 43 | // Close the USB connection 44 | usbcom.close(); 45 | } 46 | -------------------------------------------------------------------------------- /libtungsten/sam4l/interrupt_priorities.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ast.h" 3 | #include "bpm.h" 4 | #include "dma.h" 5 | #include "eic.h" 6 | #include "gpio.h" 7 | #include "i2c.h" 8 | #include "pm.h" 9 | #include "tc.h" 10 | #include "trng.h" 11 | #include "usart.h" 12 | #include "usb.h" 13 | 14 | // Note : a high number means a lower priority. 15 | // The highest priority is 1. 16 | 17 | namespace AST { 18 | uint8_t INTERRUPT_PRIORITY = 100; 19 | } 20 | 21 | namespace BPM { 22 | uint8_t INTERRUPT_PRIORITY = 2; 23 | } 24 | 25 | namespace DMA { 26 | uint8_t INTERRUPT_PRIORITY = 5; 27 | } 28 | 29 | namespace EIC { 30 | uint8_t INTERRUPT_PRIORITY = 50; 31 | } 32 | 33 | namespace GPIO { 34 | uint8_t INTERRUPT_PRIORITY = 50; 35 | } 36 | 37 | namespace I2C { 38 | uint8_t INTERRUPT_PRIORITY = 10; 39 | } 40 | 41 | namespace PM { 42 | uint8_t INTERRUPT_PRIORITY = 2; 43 | } 44 | 45 | namespace SPI { 46 | uint8_t INTERRUPT_PRIORITY = 10; 47 | } 48 | 49 | namespace TC { 50 | uint8_t INTERRUPT_PRIORITY = 40; 51 | } 52 | 53 | namespace TRNG { 54 | uint8_t INTERRUPT_PRIORITY = 50; 55 | } 56 | 57 | namespace USART { 58 | uint8_t INTERRUPT_PRIORITY = 20; 59 | } 60 | 61 | namespace USB { 62 | uint8_t INTERRUPT_PRIORITY = 8; 63 | } 64 | 65 | namespace WDT { 66 | uint8_t INTERRUPT_PRIORITY = 3; 67 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/error.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERROR_H_ 2 | #define _ERROR_H_ 3 | 4 | #include 5 | 6 | namespace Error { 7 | 8 | enum class Module { 9 | CORE, 10 | DMA, 11 | SCIF, 12 | BSCIF, 13 | PM, 14 | BPM, 15 | ADC, 16 | DAC, 17 | FLASH, 18 | GPIO, 19 | I2C, 20 | SPI, 21 | TC, 22 | USART, 23 | WDT, 24 | EIC, 25 | USB, 26 | CUSTOM 27 | }; 28 | 29 | using Code = uint16_t; 30 | 31 | enum class Severity { 32 | INFO = 0, 33 | WARNING = 1, 34 | CRITICAL = 2 35 | }; 36 | const int N_SEVERITY = 3; 37 | 38 | struct Error { 39 | unsigned long time; 40 | Module module; 41 | int userModule; 42 | Code code; 43 | Severity severity; 44 | }; 45 | 46 | const int MAX_ERROR_NUMBER = 16; 47 | 48 | void init(); 49 | void setHandler(Severity severity, void (*handler)(Module module, int userModule, Code code)); 50 | void happened(Module module, Code code, Severity severity=Severity::CRITICAL); 51 | void happened(int userModule, int code, Severity severity=Severity::CRITICAL); 52 | unsigned int getNumber(); 53 | const Error& get(unsigned int n); 54 | const Error& getLast(); 55 | 56 | } 57 | 58 | #endif -------------------------------------------------------------------------------- /libtungsten/utils/USBCom.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_COM_H 2 | #define _USB_COM_H 3 | 4 | #include 5 | 6 | namespace USBCom { 7 | 8 | enum class Event { 9 | USB_CONNECTED, 10 | USB_DISCONNECTED, 11 | COM_CONNECTED, 12 | COM_DISCONNECTED, 13 | CONTROL_REQUEST, 14 | 15 | N_EVENTS 16 | }; 17 | 18 | const uint8_t REQ_BOOTLOADER = 0x00; 19 | const uint8_t REQ_CONNECT = 0x01; 20 | const uint8_t REQ_DISCONNECT = 0x02; 21 | 22 | void enable(uint16_t vendorId=USB::DEFAULT_VENDOR_ID, uint16_t productId=USB::DEFAULT_PRODUCT_ID, uint16_t deviceRevision=USB::DEFAULT_DEVICE_REVISION); 23 | void setHandler(Event event, void (*handler)()); 24 | bool isUSBConnected(); 25 | bool isComConnected(); 26 | uint8_t getControlRequest(); 27 | int available(); 28 | int contains(uint8_t byte); 29 | uint8_t read(); 30 | int read(uint8_t* buffer, unsigned int size); 31 | void write(uint8_t byte); 32 | void write(const uint8_t* buffer, unsigned int size); 33 | void write(const char* str); 34 | void write(int number, uint8_t base=10); 35 | void write(bool boolean); 36 | void writeLine(const char* buffer, int size); 37 | void writeLine(char byte); 38 | void writeLine(int number, uint8_t base=10); 39 | void writeLine(bool boolean); 40 | 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/gloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _GLOC_H_ 2 | #define _GLOC_H_ 3 | 4 | #include 5 | #include 6 | #include "gpio.h" 7 | 8 | // Glue Logic Controller 9 | // This module manages truth tables to use some of the chip's pins 10 | // as programmable logic gates 11 | namespace GLOC { 12 | 13 | // Peripheral memory space base address 14 | const uint32_t GLOC_BASE = 0x40060000; 15 | const uint32_t GLOC_REG_SIZE = 0x08; 16 | const int N_GLOC = 2; 17 | 18 | // Registers addresses 19 | const uint32_t OFFSET_CR0 = 0x00; // Control Register 0 20 | const uint32_t OFFSET_TRUTH0 = 0x04; // Truth Table Register 0 21 | 22 | // Subregisters 23 | const uint32_t CR0_AEN = 0; 24 | const uint32_t CR0_FILTEN = 31; 25 | const uint32_t TRUTH0_TRUTH = 0; 26 | 27 | enum class LUT { 28 | LUT0 = 0, 29 | LUT1 = 1 30 | }; 31 | 32 | enum class PinFunction { 33 | IN0, 34 | IN1, 35 | IN2, 36 | IN3, 37 | OUT 38 | }; 39 | 40 | 41 | // Module functions 42 | void enable(LUT lut, bool in0, bool in1=false, bool in2=false, bool in3=false); 43 | void disable(LUT lut); 44 | void set(LUT lut, bool output, bool in0, bool in1=false, bool in2=false, bool in3=false); 45 | void setLUT(LUT lut, uint16_t truth); 46 | void enableFilter(LUT lut, SCIF::GCLKSource clock=SCIF::GCLKSource::RCSYS, uint16_t divider=10); 47 | void disableFilter(LUT lut); 48 | void setPin(LUT lut, PinFunction function, GPIO::Pin pin); 49 | 50 | } 51 | 52 | 53 | #endif -------------------------------------------------------------------------------- /libtungsten/usbcom/usbcom_gui.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from usbcom import USBCom 3 | 4 | class App: 5 | def __init__(self, root): 6 | # GUI 7 | frame = Frame(root) 8 | frame.pack(fill=BOTH, expand=True) 9 | self.txt_out = Text(frame, state=DISABLED) 10 | self.txt_out.tag_config("in", foreground="red") 11 | self.txt_out.pack(fill=BOTH, expand=True) 12 | self.txt_in = Entry(frame) 13 | self.txt_in.bind("", self.key) 14 | self.txt_in.pack(fill=X) 15 | root.update() 16 | root.minsize(width=root.winfo_width(), height=root.winfo_height()) 17 | 18 | # USBCom 19 | self.usbcom = USBCom() 20 | if not self.usbcom.connect(self.on_read): 21 | print(self.usbcom.connection_error_message) 22 | 23 | def key(self, event): 24 | if event.char == '\r': 25 | str_in = self.txt_in.get() + "\n" 26 | self.txt_out.config(state=NORMAL) 27 | self.txt_out.insert(END, str_in, "in") 28 | self.txt_out.config(state=DISABLED) 29 | self.txt_in.delete(0, END) 30 | self.usbcom.write(str_in) 31 | 32 | def on_read(self, data): 33 | self.txt_out.config(state=NORMAL) 34 | data_str = "" 35 | for b in data: 36 | data_str += chr(b) 37 | self.txt_out.insert(END, data_str) 38 | self.txt_out.config(state=DISABLED) 39 | self.txt_out.see(END) 40 | 41 | if __name__ == '__main__': 42 | root = Tk() 43 | app = App(root) 44 | root.mainloop() 45 | app.usbcom.disconnect() -------------------------------------------------------------------------------- /context.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONTEXT_H_ 2 | #define _CONTEXT_H_ 3 | 4 | #include 5 | 6 | namespace Context { 7 | 8 | extern int _menuItemSelected; 9 | extern int _submenuItemSelected; 10 | extern bool _editingItem; 11 | extern int _editingItemCursor; 12 | extern bool _btnOkPressed; 13 | extern bool _submenuFocusHold; 14 | extern bool _submenuTriggerHold; 15 | 16 | extern bool _triggerSync; 17 | extern unsigned int _delayMs; 18 | extern bool _delaySync; 19 | extern int _intervalNShots; 20 | extern unsigned int _intervalDelayMs; 21 | extern bool _intervalSync; 22 | extern int _inputMode; 23 | extern bool _inputSync; 24 | extern unsigned int _timingsFocusDurationMs; 25 | extern unsigned int _timingsTriggerDurationMs; 26 | extern bool _timingsSync; 27 | extern int _syncChannel; 28 | extern int _radio; 29 | extern int _brightness; 30 | 31 | extern Core::Time _tFocus; 32 | extern Core::Time _tTrigger; 33 | extern bool _inhibitTriggerHold; 34 | extern bool _skipDelay; 35 | extern int _shotsLeft; 36 | extern unsigned int _countdown; 37 | 38 | extern int _vBat; 39 | 40 | extern unsigned int _shadowDelayMs; 41 | extern int _shadowIntervalNShots; 42 | extern unsigned int _shadowIntervalDelayMs; 43 | extern unsigned int _shadowTimingsFocusDurationMs; 44 | extern unsigned int _shadowTimingsTriggerDurationMs; 45 | 46 | extern int _rssi; 47 | extern Core::Time _tReceivedCommand; 48 | const int RSSI_TIMEOUT = 1000; 49 | const int RSSI_MID = -100; 50 | const int RSSI_HIGH = -80; 51 | 52 | void read(); 53 | void save(); 54 | 55 | } 56 | 57 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/error.cpp: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | #include "core.h" 3 | 4 | namespace Error { 5 | 6 | Error errors[MAX_ERROR_NUMBER]; 7 | int nErrors = 0; 8 | 9 | void (*handlers[N_SEVERITY])(Module module, int userModule, Code code); 10 | 11 | void init() { 12 | for (int i = 0; i < N_SEVERITY; i++) { 13 | handlers[i] = nullptr; 14 | } 15 | } 16 | 17 | void setHandler(Severity severity, void (*handler)(Module module, int userModule, Code code)) { 18 | handlers[static_cast(severity)] = handler; 19 | } 20 | 21 | void happened(Module module, int userModule, Code code, Severity severity) { 22 | if (nErrors < MAX_ERROR_NUMBER) { 23 | Error& error = errors[nErrors]; 24 | error.time = Core::time(); 25 | error.module = module; 26 | error.userModule = userModule; 27 | error.code = code; 28 | error.severity = severity; 29 | nErrors++; 30 | } 31 | if (handlers[static_cast(severity)] != nullptr) { 32 | handlers[static_cast(severity)](module, userModule, code); 33 | } 34 | } 35 | 36 | void happened(Module module, Code code, Severity severity) { 37 | happened(module, -1, code, severity); 38 | } 39 | 40 | void happened(int userModule, int code, Severity severity) { 41 | happened(static_cast(-1), userModule, static_cast(code), severity); 42 | } 43 | 44 | unsigned int getNumber() { 45 | return nErrors; 46 | } 47 | 48 | const Error& get(unsigned int n) { 49 | return errors[n]; 50 | } 51 | 52 | const Error& getLast() { 53 | return errors[nErrors - 1]; 54 | } 55 | } -------------------------------------------------------------------------------- /drivers/oled_ssd1306/font.h: -------------------------------------------------------------------------------- 1 | #ifndef _FONT_H_ 2 | #define _FONT_H_ 3 | 4 | #include 5 | 6 | namespace Font { 7 | struct Char5 { 8 | const unsigned int width; 9 | const unsigned int height; 10 | const uint8_t bitmap[5]; 11 | }; 12 | struct Char8 { 13 | const unsigned int width; 14 | const unsigned int height; 15 | const uint8_t bitmap[8]; 16 | }; 17 | struct Char16 { 18 | const unsigned int width; 19 | const unsigned int height; 20 | const uint16_t bitmap[16]; 21 | }; 22 | struct Char32 { 23 | const unsigned int width; 24 | const unsigned int height; 25 | const uint32_t bitmap[32]; 26 | }; 27 | struct Char64 { 28 | const unsigned int width; 29 | const unsigned int height; 30 | const uint64_t bitmap[64]; 31 | }; 32 | 33 | enum class Size { 34 | SMALL=0, 35 | MEDIUM=1, 36 | LARGE=2, 37 | 38 | N_SIZES 39 | }; 40 | 41 | //const unsigned int HEIGHT_SMALL = 5; 42 | //const unsigned int HEIGHT_MEDIUM = 8; 43 | //const unsigned int HEIGHT_LARGE = 16; 44 | //const unsigned int HEIGHT_XLARGE = 32; 45 | const unsigned int HEIGHT[] = {5, 8, 16, 32}; 46 | const unsigned int WIDTH[] = {5, 5, 10, 14}; 47 | 48 | const unsigned int N_CHARS_TOTAL = 96; 49 | const unsigned int N_CHARS_SMALL = 96; 50 | const unsigned int N_CHARS_MEDIUM = 96; 51 | const unsigned int N_CHARS_LARGE = 68; 52 | extern const Char5 fontSmall[N_CHARS_SMALL]; 53 | extern const Char8 fontMedium[N_CHARS_MEDIUM]; 54 | extern const Char16 fontLarge[N_CHARS_LARGE]; 55 | 56 | Char5 getSmall(char c); 57 | Char8 getMedium(char c); 58 | Char16 getLarge(char c); 59 | 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /libtungsten/utils/Servo.cpp: -------------------------------------------------------------------------------- 1 | #include "Servo.h" 2 | 3 | // Constructor : must specify the underlying TC channel to use 4 | Servo::Servo(TC::Channel tcChannel, GPIO::Pin pin) { 5 | // Save the parameters 6 | _tcChannel = tcChannel; 7 | _pin = pin; 8 | 9 | // Default values 10 | _percent = 50; 11 | _disabled = true; 12 | 13 | // If a custom pin is specified, set it 14 | if (pin.number != 0xFF) { 15 | TC::setPin(tcChannel, TC::PinFunction::OUT, pin); 16 | } 17 | 18 | // Initialize the TC channel to output the PWM signal 19 | TC::init(tcChannel, DEFAULT_PERIOD, 0, true); 20 | 21 | // Set default timings 22 | setPWMTimings(); 23 | } 24 | 25 | // Set the servo position in percent 26 | // This will translate to different angles according to the angular range of the servo 27 | void Servo::set(unsigned int percent) { 28 | // Check value 29 | if (percent > 100) { 30 | percent = 100; 31 | } 32 | 33 | // Save the value 34 | _disabled = false; 35 | _percent = percent; 36 | 37 | // Compute and set the hightime 38 | TC::setHighTime(_tcChannel, _highTime0 + percent * (_highTime100 - _highTime0) / 100); 39 | } 40 | 41 | void Servo::disable() { 42 | _disabled = true; 43 | TC::setHighTime(_tcChannel, 0); 44 | } 45 | 46 | // Customize the PWM timings 47 | // Passing no argument resets the default values 48 | void Servo::setPWMTimings(unsigned int highTime0, unsigned int highTime100, unsigned int period) { 49 | // Save the timings 50 | _highTime0 = highTime0; 51 | _highTime100 = highTime100; 52 | _period = period; 53 | 54 | // Reset the high time 55 | TC::setHighTime(_tcChannel, 0); 56 | 57 | // Set the period 58 | TC::setPeriod(_tcChannel, period); 59 | 60 | // Recalculate the hightime based on the new timings 61 | if (!_disabled) { 62 | set(_percent); 63 | } 64 | } -------------------------------------------------------------------------------- /libtungsten/utils/RingBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _RING_BUFFER_H_ 2 | #define _RING_BUFFER_H_ 3 | 4 | #include 5 | 6 | class RingBuffer { 7 | private: 8 | uint8_t* _buffer = nullptr; 9 | unsigned int _capacity = 0; 10 | unsigned int _cursorR = 0; 11 | unsigned int _cursorW = 0; 12 | bool _empty = true; 13 | bool _overflow = false; 14 | bool _underflow = false; 15 | 16 | public: 17 | // Constructor : must be passed the buffer to use 18 | RingBuffer(uint8_t* buffer, unsigned int capacity); 19 | 20 | // Get the value of a random byte in the buffer, without 21 | // changing the cursors 22 | uint8_t operator[](unsigned int i) const; 23 | 24 | // Read one byte from the internal buffer 25 | uint8_t read(); 26 | 27 | // Read some bytes from the internal buffer 28 | int read(uint8_t* buffer, unsigned int size); 29 | 30 | // Write one byte into the internal buffer 31 | void write(uint8_t byte); 32 | 33 | // Write some bytes into the internal buffer 34 | void write(const uint8_t* buffer, unsigned int size); 35 | 36 | // Number of bytes currently stored in the buffer 37 | unsigned int size() const; 38 | 39 | // Check if the buffer is empty 40 | inline bool isEmpty() { return size() == 0; } 41 | 42 | // Check if the specified byte is in the buffer 43 | int contains(uint8_t byte) const; 44 | 45 | // Internal buffer total capacity 46 | unsigned int capacity() const; 47 | 48 | // Return true if the internal buffer is overflown 49 | // (too many writes, not enough reads) 50 | bool isOverflow() const; 51 | 52 | // Return true if the user attempted to read more bytes than 53 | // were available 54 | bool isUnderflow() const; 55 | 56 | // Revert the ring buffer to its initial state : 57 | // cursors and overflow/underflow flags are reset 58 | void reset(); 59 | 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /icons/bitmap_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | if len(sys.argv) < 2: 7 | print("Usage : " + sys.argv[0] + " FILE...", file=sys.stderr) 8 | sys.exit(0) 9 | 10 | for i in range(len(sys.argv) - 1): 11 | filename = sys.argv[i + 1] 12 | with open(filename, "r") as file: 13 | magic = file.readline().strip() 14 | if magic != "P1": 15 | print("Invalid file magic number : '" + magic + "'", file=sys.stderr) 16 | sys.exit(0) 17 | dimensions = file.readline() 18 | while dimensions.startswith("#"): 19 | dimensions = file.readline() 20 | width = int(dimensions.split(" ")[0].strip()) 21 | height = int(dimensions.split(" ")[1].strip()) 22 | if height not in [5, 8, 16, 32, 64]: 23 | print("Only heights of 5, 8, 16, 32 or 64 are supported", file=sys.stderr) 24 | sys.exit(0) 25 | dataRaw = file.read() 26 | data = "" 27 | for c in dataRaw: 28 | if c == "0" or c == "1": 29 | data += c 30 | if len(data) != width * height: 31 | print("Invalid data length " + len(data) + ", expected " + str(width) + "x" + str(height) + "=" + str(width*height), file=sys.stderr) 32 | sys.exit(0) 33 | #print("Width : " + str(width)) 34 | #print("Height : " + str(height)) 35 | #print("Data : " + data) 36 | print("const Font::Char" + str(height) + " ICON_" + filename.split(".")[0].upper() + " = {") 37 | print(" " + str(width) + ",") 38 | print(" " + str(height) + ",") 39 | print(" {") 40 | for x in range(width): 41 | print(" 0b" + "".join([str(data[x + (height - y - 1) * width]) for y in range(height)]) + ",") 42 | print(" }") 43 | print("};") -------------------------------------------------------------------------------- /libtungsten/sam4l/dac.h: -------------------------------------------------------------------------------- 1 | #ifndef _DAC_H_ 2 | #define _DAC_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | 7 | // Digital to Analog Converter 8 | // This module is used to generate an analog voltage on a pin 9 | namespace DAC { 10 | 11 | // Peripheral memory space base address 12 | const uint32_t DAC_BASE = 0x4003C000; 13 | 14 | // Registers addresses 15 | const uint32_t OFFSET_CR = 0x00; // Control Register 16 | const uint32_t OFFSET_MR = 0x04; // Mode Register 17 | const uint32_t OFFSET_CDR = 0x08; // Conversion Data Register 18 | const uint32_t OFFSET_IER = 0x0C; // Interrupt Enable Register 19 | const uint32_t OFFSET_IDR = 0x10; // Interrupt Disable Register 20 | const uint32_t OFFSET_IMR = 0x14; // Interrupt Mask Register 21 | const uint32_t OFFSET_ISR = 0x18; // Interrupt Status Register 22 | const uint32_t OFFSET_WPMR = 0xE4; // Write Protect Mode Register 23 | const uint32_t OFFSET_WPSR = 0xE8; // Write Protect Status Register 24 | 25 | // Constants 26 | const uint32_t CR_SWRST = 0; 27 | const uint32_t MR_TRGEN = 0; 28 | const uint32_t MR_TRGSEL = 1; 29 | const uint32_t MR_DACEN = 4; 30 | const uint32_t MR_WORD = 5; 31 | const uint32_t MR_STARTUP = 8; 32 | const uint32_t MR_CLKDIV = 16; 33 | const uint32_t WPMR_WPEN = 0; 34 | const uint32_t WPMR_WPKEY = 0x444143 << 8; 35 | 36 | enum class Interrupt { 37 | RELOAD_EMPTY, 38 | TRANSFER_FINISHED 39 | }; 40 | 41 | 42 | // Module API 43 | void enable(); 44 | void disable(); 45 | void write(uint16_t value); // 0 <= value <= 1023 46 | void start(uint16_t* buffer, int n, bool repeat=false); 47 | void reload(uint16_t* buffer, int n); 48 | void stop(); 49 | bool setFrequency(unsigned long frequency); 50 | bool isFinished(); 51 | bool isReloadEmpty(); 52 | void enableInterrupt(void (*handler)(), Interrupt interrupt=Interrupt::TRANSFER_FINISHED); 53 | void disableInterrupt(Interrupt interrupt=Interrupt::TRANSFER_FINISHED); 54 | void setPin(GPIO::Pin pin); 55 | 56 | } 57 | 58 | 59 | #endif -------------------------------------------------------------------------------- /libtungsten/carbide/carbide.h: -------------------------------------------------------------------------------- 1 | #ifndef _CARBIDE_H_ 2 | #define _CARBIDE_H_ 3 | 4 | #include 5 | 6 | #if PACKAGE != 64 7 | #warning "You are compiling for the Carbide with an incorrect package, please set PACKAGE=64 in your Makefile" 8 | #endif 9 | 10 | namespace Carbide { 11 | 12 | // Pins definition 13 | const GPIO::Pin PIN_LED_R = GPIO::PA00; 14 | const GPIO::Pin PIN_LED_G = GPIO::PA01; 15 | const GPIO::Pin PIN_LED_B = GPIO::PA02; 16 | const GPIO::Pin PIN_BUTTON = GPIO::PA04; 17 | 18 | // Predefined CPU frequencies 19 | enum class CPUFreq { 20 | FREQ_4MHZ, 21 | FREQ_8MHZ, 22 | FREQ_12MHZ, 23 | FREQ_24MHZ, 24 | FREQ_36MHZ, 25 | FREQ_48MHZ 26 | }; 27 | 28 | // Helper functions 29 | void init(bool autoBootloaderReset=false); 30 | void setCPUFrequency(CPUFreq frequency); 31 | void warningHandler(Error::Module module, int userModule, Error::Code code); 32 | void criticalHandler(Error::Module module, int userModule, Error::Code code); 33 | inline void initLedR() { GPIO::enableOutput(PIN_LED_R, GPIO::HIGH); } 34 | inline void setLedR(bool on=true) { GPIO::set(PIN_LED_R, !on); } // Inverted : pin must be LOW to turn the LED on 35 | inline void initLedG() { GPIO::enableOutput(PIN_LED_G, GPIO::HIGH); } 36 | inline void setLedG(bool on=true) { GPIO::set(PIN_LED_G, !on); } 37 | inline void initLedB() { GPIO::enableOutput(PIN_LED_B, GPIO::HIGH); } 38 | inline void setLedB(bool on=true) { GPIO::set(PIN_LED_B, !on); } 39 | inline void initLeds() { initLedR(); initLedG(); initLedB(); } 40 | inline void initButton() { GPIO::enableInput(PIN_BUTTON, GPIO::Pulling::PULLUP); } 41 | inline bool isButtonPressed() { return !GPIO::get(PIN_BUTTON); } // Inverted : the pin is LOW when the button is pressed (pullup) 42 | void onButtonPressed(void (*handler)(), bool released=false); 43 | inline bool buttonRisingEdge() { return GPIO::fallingEdge(PIN_BUTTON); } // Rising/falling are also inverted for the same reasons 44 | inline bool buttonFallingEdge() { return GPIO::risingEdge(PIN_BUTTON); } 45 | inline void waitButtonPressed() { while (!buttonRisingEdge()); } 46 | 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/trng.cpp: -------------------------------------------------------------------------------- 1 | #include "trng.h" 2 | #include "core.h" 3 | #include "pm.h" 4 | 5 | namespace TRNG { 6 | 7 | // Interrupt handler 8 | extern uint8_t INTERRUPT_PRIORITY; 9 | uint32_t _dataReadyHandler = 0; 10 | void interruptHandlerWrapper(); 11 | 12 | void enable() { 13 | // Enable the clock 14 | PM::enablePeripheralClock(PM::CLK_TRNG); 15 | 16 | // CR (Control Register) : enable the TRNG 17 | (*(volatile uint32_t*)(BASE + OFFSET_CR)) 18 | = 1 << CR_ENABLE 19 | | CR_KEY; 20 | } 21 | 22 | bool available() { 23 | // Return true if a new random number is available 24 | return (*(volatile uint32_t*)(BASE + OFFSET_ISR)) & 1 << ISR_DATRDY; 25 | } 26 | 27 | uint32_t get() { 28 | // Clear the DATARDY bit by reading ISR 29 | available(); 30 | 31 | // Return the new random number 32 | return (*(volatile uint32_t*)(BASE + OFFSET_ODATA)); 33 | } 34 | 35 | void enableInterrupt(void (*handler)(uint32_t)) { 36 | // Save the user handler 37 | _dataReadyHandler = (uint32_t)handler; 38 | 39 | // IER (Interrupt Enable Register) : enable the Data Ready interrupt (this is the 40 | // only interrupt available) 41 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) 42 | = 1 << ISR_DATRDY; 43 | 44 | // Set the handler and enable the module interrupt at the Core level 45 | Core::setInterruptHandler(Core::Interrupt::TRNG, interruptHandlerWrapper); 46 | Core::enableInterrupt(Core::Interrupt::TRNG, INTERRUPT_PRIORITY); 47 | } 48 | 49 | void disableInterrupt() { 50 | // IER (Interrupt Disable Register) : disable the interrupt 51 | (*(volatile uint32_t*)(BASE + OFFSET_IDR)) 52 | = 1 << ISR_DATRDY; 53 | 54 | // Disable the module interrupt at the Core level 55 | Core::disableInterrupt(Core::Interrupt::TRNG); 56 | } 57 | 58 | void interruptHandlerWrapper() { 59 | // Call the user handler 60 | void (*handler)(uint32_t) = (void (*)(uint32_t))_dataReadyHandler; 61 | if (handler != nullptr) { 62 | handler(get()); 63 | } 64 | 65 | // Clear the interrupt by reading ISR 66 | available(); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/eic.h: -------------------------------------------------------------------------------- 1 | #ifndef _EIC_H_ 2 | #define _EIC_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | #include "error.h" 7 | 8 | // External Interrupt Controller 9 | // This module manages synchronous and asynchronous interrupts 10 | // which are able to wake the chip up from power save mode 11 | namespace EIC { 12 | 13 | // Peripheral memory space base address 14 | const uint32_t BASE = 0x400F1000; 15 | 16 | 17 | // Registers addresses 18 | const uint32_t OFFSET_IER = 0x000; // Interrupt Enable Register 19 | const uint32_t OFFSET_IDR = 0x004; // Interrupt Disable Register 20 | const uint32_t OFFSET_IMR = 0x008; // Interrupt Mask Register 21 | const uint32_t OFFSET_ISR = 0x00C; // Interrupt Status Register 22 | const uint32_t OFFSET_ICR = 0x010; // Interrupt Clear Register 23 | const uint32_t OFFSET_MODE = 0x014; // Mode Register 24 | const uint32_t OFFSET_EDGE = 0x018; // Edge Register 25 | const uint32_t OFFSET_LEVEL = 0x01C; // Level Register 26 | const uint32_t OFFSET_FILTER = 0x020; // Filter Register 27 | const uint32_t OFFSET_TEST = 0x024; // Test Register 28 | const uint32_t OFFSET_ASYNC = 0x028; // Asynchronous Register 29 | const uint32_t OFFSET_EN = 0x030; // Enable Register 30 | const uint32_t OFFSET_DIS = 0x034; // Disable Register 31 | const uint32_t OFFSET_CTRL = 0x038; // Control Register 32 | 33 | // Constants 34 | const int NMI = 0; // EIC interrupt 0 is the NMI 35 | const int N_CHANNELS = 9; 36 | 37 | // Error codes 38 | const Error::Code ERR_UNKNOWN_CHANNEL = 0x0001; 39 | 40 | enum class Mode { 41 | EDGE = 0, 42 | LEVEL = 1, 43 | }; 44 | 45 | enum class Polarity { 46 | LOW_FALLING = 0, 47 | HIGH_RISING = 1, 48 | }; 49 | 50 | using Channel = unsigned int; 51 | 52 | 53 | // Module API 54 | void setPin(Channel channel, GPIO::Pin pin); 55 | void enableInterrupt(Channel channel, Mode mode, Polarity polarity, void (*handler)(int), bool filter=true); 56 | void enableAsyncInterrupt(Channel channel, Polarity polarity, void (*handler)(int)=nullptr); 57 | void disableInterrupt(Channel channel); 58 | void clearInterrupt(Channel channel); 59 | 60 | 61 | } 62 | 63 | 64 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/wdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDT_H_ 2 | #define _WDT_H_ 3 | 4 | #include 5 | 6 | // Watchdog Timer 7 | // This module is able to automatically reset the chip after a 8 | // specified delay unless it is periodically serviced. This is 9 | // useful to recover from an unexpected behaviour which leads the 10 | // execution to hang. 11 | namespace WDT { 12 | 13 | // Peripheral memory space base address 14 | const uint32_t WDT_BASE = 0x400F0C00; 15 | 16 | 17 | // Registers addresses 18 | const uint32_t OFFSET_CTRL = 0x000; // Control Register 19 | const uint32_t OFFSET_CLR = 0x004; // Clear Register 20 | const uint32_t OFFSET_SR = 0x008; // Status Register 21 | const uint32_t OFFSET_IER = 0x00C; // Interrupt Enable Register 22 | const uint32_t OFFSET_IDR = 0x010; // Interrupt Disable Register 23 | const uint32_t OFFSET_IMR = 0x014; // Interrupt Mask Register 24 | const uint32_t OFFSET_ISR = 0x018; // Interrupt Status Register 25 | const uint32_t OFFSET_ICR = 0x01C; // Interrupt Clear Register 26 | 27 | 28 | // Subregisters 29 | const uint32_t CTRL_EN = 0; // WDT Enable 30 | const uint32_t CTRL_DAR = 1; // WDT Disable After Reset 31 | const uint32_t CTRL_MODE = 2; // WDT Mode 32 | const uint32_t CTRL_SFV = 3; // WDT Control Register Store Final Value 33 | const uint32_t CTRL_IM = 4; // Interrupt Mode 34 | const uint32_t CTRL_FCD = 7; // Flash Calibration Done 35 | const uint32_t CTRL_PSEL = 8; // Timeout Prescale Select 36 | const uint32_t CTRL_CEN = 16; // Clock Enable 37 | const uint32_t CTRL_CSSEL = 17; // Clock Source Select 38 | const uint32_t CTRL_TBAN = 18; // Time Ban Prescale Select 39 | const uint32_t CTRL_KEY = 24; // Key 40 | const uint32_t CLR_WDTCLR = 0; // Watchdog Clear 41 | const uint32_t CLR_KEY = 24; // Key 42 | const uint32_t SR_WINDOW = 0; // Counter inside the PSEL period 43 | const uint32_t SR_CLEARED = 1; // WDT cleared 44 | const uint32_t ISR_WINT = 2; // Watchdog interrupt 45 | 46 | 47 | // Constants 48 | const uint32_t CTRL_KEY_1 = 0x55 << CTRL_KEY; 49 | const uint32_t CTRL_KEY_2 = 0xAA << CTRL_KEY; 50 | const uint32_t CLR_KEY_1 = 0x55 << CLR_KEY; 51 | const uint32_t CLR_KEY_2 = 0xAA << CLR_KEY; 52 | 53 | 54 | enum class Unit { 55 | MILLISECONDS, 56 | MICROSECONDS 57 | }; 58 | 59 | // Module API 60 | void enable(unsigned int timeout, Unit unit=Unit::MILLISECONDS, void (*timeoutHandler)()=nullptr, unsigned int windowStart=0, bool useOSC32K=true); 61 | void disable(); 62 | bool isEnabled(); 63 | void clear(); 64 | void clearInterrupt(); 65 | 66 | } 67 | 68 | 69 | #endif -------------------------------------------------------------------------------- /pins.h: -------------------------------------------------------------------------------- 1 | #ifndef _PINS_H_ 2 | #define _PINS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // I2C 9 | const I2C::Port I2C_PORT = I2C::Port::I2C1; 10 | const GPIO::Pin PIN_I2C_SDA = {GPIO::Port::B, 0, GPIO::Periph::A}; 11 | const GPIO::Pin PIN_I2C_SCL = {GPIO::Port::B, 1, GPIO::Periph::A}; 12 | 13 | // SPI 14 | const GPIO::Pin PIN_MISO = {GPIO::Port::A, 27, GPIO::Periph::A}; 15 | const GPIO::Pin PIN_MOSI = {GPIO::Port::A, 28, GPIO::Periph::A}; 16 | const GPIO::Pin PIN_SCK = {GPIO::Port::A, 29, GPIO::Periph::A}; 17 | 18 | // OLED 19 | const SPI::Peripheral SPI_SLAVE_OLED = 0; 20 | const GPIO::Pin PIN_OLED_CS = {GPIO::Port::A, 30, GPIO::Periph::A}; 21 | const GPIO::Pin PIN_OLED_RES = GPIO::PB02; 22 | const GPIO::Pin PIN_OLED_DC = GPIO::PB03; 23 | 24 | // LoRa 25 | const SPI::Peripheral SPI_SLAVE_LORA = 1; 26 | const GPIO::Pin PIN_LORA_CS = {GPIO::Port::A, 31, GPIO::Periph::A}; 27 | const GPIO::Pin PIN_LORA_RESET = GPIO::PA09; 28 | const GPIO::Pin PIN_LORA_DIO0 = GPIO::PA07; 29 | const GPIO::Pin PIN_LORA_DIO1 = GPIO::PA06; 30 | const GPIO::Pin PIN_LORA_DIO2 = GPIO::PB05; 31 | const GPIO::Pin PIN_LORA_DIO3 = GPIO::PB06; 32 | const GPIO::Pin PIN_LORA_DIO4 = GPIO::PA08; 33 | const GPIO::Pin PIN_LORA_DIO5 = GPIO::PB07; 34 | 35 | // Buttons 36 | const GPIO::Pin PIN_BTN_UP = GPIO::PA19; 37 | const GPIO::Pin PIN_BTN_DOWN = GPIO::PA10; 38 | const GPIO::Pin PIN_BTN_LEFT = GPIO::PA11; 39 | const GPIO::Pin PIN_BTN_RIGHT = GPIO::PA13; 40 | const GPIO::Pin PIN_BTN_OK = GPIO::PA14; 41 | const GPIO::Pin PIN_BTN_PW = GPIO::PA01; 42 | const GPIO::Pin PIN_BTN_FOCUS = GPIO::PB04; 43 | const GPIO::Pin PIN_BTN_TRIGGER = GPIO::PA18; 44 | 45 | // LEDs 46 | const GPIO::Pin PIN_LED_FOCUS = GPIO::PA20; 47 | const GPIO::Pin PIN_LED_TRIGGER = GPIO::PB11; 48 | const GPIO::Pin PIN_LED_INPUT = GPIO::PB15; 49 | 50 | // Jack ports 51 | const GPIO::Pin PIN_P1_T = GPIO::PA17; 52 | const GPIO::Pin PIN_P1_T_PD = GPIO::PB08; 53 | const GPIO::Pin PIN_P1_R1 = GPIO::PB09; 54 | const GPIO::Pin PIN_P1_R1_PD = GPIO::PB10; 55 | const GPIO::Pin PIN_P1_R2 = GPIO::PA12; 56 | const GPIO::Pin PIN_P1_R2_PD = GPIO::PA16; 57 | const GPIO::Pin PIN_P1_SW = GPIO::PA15; 58 | const GPIO::Pin PIN_P2_T = GPIO::PB13; 59 | const GPIO::Pin PIN_P2_T_PD = GPIO::PB12; 60 | const GPIO::Pin PIN_P2_R1 = GPIO::PA23; 61 | const GPIO::Pin PIN_P2_R1_PD = GPIO::PA24; 62 | const GPIO::Pin PIN_P2_R2 = GPIO::PB14; 63 | const GPIO::Pin PIN_P2_R2_PD = GPIO::PA22; 64 | const GPIO::Pin PIN_P2_SW = GPIO::PA21; 65 | 66 | // Power enable command 67 | const GPIO::Pin PIN_PW_EN = GPIO::PA00; 68 | 69 | // Battery voltage measurement 70 | const GPIO::Pin PIN_VBAT_MEAS = {GPIO::Port::A, 4, GPIO::Periph::A}; 71 | const int ADC_VBAT = 0; 72 | const GPIO::Pin PIN_VBAT_MEAS_CMD = GPIO::PA05; 73 | 74 | // Aliases for features of the jack ports 75 | const GPIO::Pin PIN_INPUT = PIN_P2_T; 76 | const GPIO::Pin PIN_FOCUS = PIN_P1_R1_PD; 77 | const GPIO::Pin PIN_TRIGGER = PIN_P1_T_PD; 78 | 79 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/ast.h: -------------------------------------------------------------------------------- 1 | #ifndef _AST_H_ 2 | #define _AST_H_ 3 | 4 | #include 5 | 6 | // Asynchronous Timer 7 | // This module manages the 32-bit asynchronous timer/counter 8 | // which is used as a system time (with a 2-ms resolution) and is able 9 | // to wake up the chip at a specific time 10 | namespace AST { 11 | 12 | // Peripheral memory space base address 13 | const uint32_t BASE = 0x400F0800; 14 | 15 | // Registers addresses 16 | const uint32_t OFFSET_CR = 0x000; // Control Register 17 | const uint32_t OFFSET_CV = 0x004; // Control Value Register 18 | const uint32_t OFFSET_SR = 0x008; // Status Register 19 | const uint32_t OFFSET_SCR = 0x00C; // Status Clear Register 20 | const uint32_t OFFSET_IER = 0x010; // Interrupt Enable Register 21 | const uint32_t OFFSET_IDR = 0x014; // Interrupt Disable Register 22 | const uint32_t OFFSET_IMR = 0x018; // Interrupt Mask Register 23 | const uint32_t OFFSET_WER = 0x01C; // Wake Enable Register 24 | const uint32_t OFFSET_AR0 = 0x020; // Alarm Register 0 25 | //const uint32_t OFFSET_AR1 = 0x024; // Alarm Register 1 -- not implemented 26 | const uint32_t OFFSET_PIR0 = 0x030; // Periodic Interval Register 0 27 | //const uint32_t OFFSET_PIR1 = 0x034; // Periodic Interval Register 1 -- not implemented 28 | const uint32_t OFFSET_CLOCK = 0x040; // Clock Control Register 29 | const uint32_t OFFSET_DTR = 0x044; // Digital Tuner Register 30 | const uint32_t OFFSET_EVE = 0x048; // Event Enable Register 31 | const uint32_t OFFSET_EVD = 0x04C; // Event Disable Register 32 | const uint32_t OFFSET_EVM = 0x050; // Event Mask Register 33 | const uint32_t OFFSET_CALV = 0x054; // Calendar Value Register 34 | 35 | // Subregisters 36 | const uint32_t CR_EN = 0; 37 | const uint32_t CR_PCLR = 1; 38 | const uint32_t CR_CAL = 2; 39 | const uint32_t CR_CA0 = 8; 40 | const uint32_t CR_PSEL = 16; 41 | const uint32_t SR_OVF = 0; 42 | const uint32_t SR_ALARM0 = 8; 43 | const uint32_t SR_PER0 = 16; 44 | const uint32_t SR_BUSY = 24; 45 | const uint32_t SR_READY = 25; 46 | const uint32_t SR_CLKBUSY = 28; 47 | const uint32_t SR_CLKRDY = 29; 48 | const uint32_t CLOCK_CEN = 0; 49 | const uint32_t CLOCK_CSSEL = 8; 50 | const uint32_t DTR_EXP = 0; 51 | const uint32_t DTR_ADD = 5; 52 | const uint32_t DTR_VALUE = 8; 53 | 54 | using Time = volatile uint64_t; 55 | extern Time _currentTimeHighBytes; 56 | 57 | 58 | // Module API 59 | void init(); 60 | inline Time time() { return ((_currentTimeHighBytes + (*(volatile uint32_t*)(BASE + OFFSET_CV))) * 1000) / (32768/2); }; 61 | void enableAlarm(Time time, bool relative=true, void (*handler)()=nullptr, bool wake=true); 62 | void disableAlarm(); 63 | bool alarmPassed(); 64 | 65 | } 66 | 67 | 68 | #endif -------------------------------------------------------------------------------- /libtungsten/bootloader/bootloader_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOOTLOADER_CONFIG_H_ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // ## Bootloader configuration 9 | 10 | // If Input mode is enabled, the bootloader will check the value of the PIN_INPUT pin 11 | // at startup and will be activated only if this pin is in the given PIN_INPUT_STATE. 12 | // An optional pulling can be activated to default to a given state if no voltage is applied 13 | // on the input. 14 | // A common scenario is to set the input on a button wired to short the line to ground when 15 | // pressed, with PIN_INPUT_STATE = GPIO::LOW and PIN_INPUT_PULLING = GPIO::Pulling::PULLUP. 16 | // With this configuration, the pullup will raise the line to HIGH by default, and the 17 | // bootloader will be activated only if the line is forced to LOW by pressing the button 18 | // during startup. 19 | const bool MODE_INPUT = true; 20 | const GPIO::Pin INPUT_PIN = GPIO::PB10; 21 | const GPIO::PinState INPUT_PIN_STATE = GPIO::LOW; 22 | const GPIO::Pulling INPUT_PIN_PULLING = GPIO::Pulling::PULLUP; 23 | 24 | // If Timeout mode is enabled, the bootloader will always be activated when the chip 25 | // is powered up, but will automatically exit and reset after the given TIMEOUT_DELAY 26 | // (in milliseconds) if no connection was detected. 27 | const bool MODE_TIMEOUT = false; 28 | const unsigned int TIMEOUT_DELAY = 3000; // ms 29 | 30 | // Enable the USB channel to allow the bootloader to register as a USB device on a connected 31 | // host. This is the easiest way to upload programs to the microcontroller using the 32 | // codeuploader tool included with the library. 33 | const bool CHANNEL_USB_ENABLED = true; 34 | const uint16_t USB_VENDOR_ID = USB::DEFAULT_VENDOR_ID; 35 | const uint16_t USB_PRODUCT_ID = 0xcbd0; 36 | 37 | // Enable the USART channel to allow the bootloader to receive instructions via a serial 38 | // connection. The port, pins and baudrate can be customized. See pins_sam4l_XX.cpp 39 | // for the list of available pins. 40 | const bool CHANNEL_USART_ENABLED = false; 41 | const USART::Port USART_PORT = USART::Port::USART0; 42 | const int USART_BAUDRATE = 115200; 43 | const GPIO::Pin USART_PIN_RX = {GPIO::Port::A, 11, GPIO::Periph::A}; 44 | const GPIO::Pin USART_PIN_TX = {GPIO::Port::A, 12, GPIO::Periph::A}; 45 | const int USART_TIMEOUT = 3000; 46 | 47 | // The bootloader can flash some LEDs to show its status. These can be enabled/disabled 48 | // and customized here. The LED_POLARITY option specifies the state to set to turn the 49 | // LED on. 50 | const bool LED_BL_ENABLED = true; 51 | const GPIO::Pin PIN_LED_BL = GPIO::PB13; 52 | const bool LED_WRITE_ENABLED = true; 53 | const GPIO::Pin PIN_LED_WRITE = GPIO::PB12; 54 | const bool LED_ERROR_ENABLED = true; 55 | const GPIO::Pin PIN_LED_ERROR = GPIO::PB12; 56 | const GPIO::PinState LED_POLARITY = GPIO::LOW; 57 | const unsigned int LED_BL_BLINK_DELAY_STANDBY = 200; // ms 58 | const unsigned int LED_BL_BLINK_DELAY_CONNECTED = 50; // ms 59 | 60 | #endif -------------------------------------------------------------------------------- /gui.h: -------------------------------------------------------------------------------- 1 | #ifndef _GUI_H_ 2 | #define _GUI_H_ 3 | 4 | #include 5 | #include "drivers/oled_ssd1306/oled.h" 6 | #include "context.h" 7 | 8 | namespace GUI { 9 | 10 | const int N_MENU_ITEMS = 6; 11 | 12 | const int PANNEL_MENU = 0; 13 | const int PANNEL_LORA_TEST = 1; 14 | const int MENU_TRIGGER = 0; 15 | const int SUBMENU_TRIGGER_FOCUS = 1; 16 | const int SUBMENU_TRIGGER_SHOOT = 2; 17 | const int SUBMENU_TRIGGER_SYNC = 3; 18 | const int MENU_DELAY = 1; 19 | const int SUBMENU_DELAY_DELAY = 1; 20 | const int SUBMENU_DELAY_SYNC = 2; 21 | const int MENU_INTERVAL = 2; 22 | const int SUBMENU_INTERVAL_SHOTS = 1; 23 | const int SUBMENU_INTERVAL_DELAY = 2; 24 | const int SUBMENU_INTERVAL_SYNC = 3; 25 | const int MENU_TIMINGS = 3; 26 | const int SUBMENU_TIMINGS_FOCUS_DURATION = 1; 27 | const int SUBMENU_TIMINGS_TRIGGER_DURATION = 2; 28 | const int SUBMENU_TIMINGS_SYNC = 3; 29 | const int MENU_INPUT = 4; 30 | const int SUBMENU_INPUT_MODE = 1; 31 | const int SUBMENU_INPUT_MODE_DISABLED = 0; 32 | const int SUBMENU_INPUT_MODE_TRIGGER = 1; 33 | const int SUBMENU_INPUT_MODE_TRIGGER_NODELAY = 2; 34 | const int SUBMENU_INPUT_MODE_PASSTHROUGH = 3; 35 | const int SUBMENU_INPUT_SYNC = 2; 36 | const int MENU_SETTINGS = 5; 37 | const int SUBMENU_SETTINGS_RADIO = 1; 38 | const int SUBMENU_SETTINGS_RADIO_DISABLED = 0; 39 | const int SUBMENU_SETTINGS_RADIO_RX_ONLY = 1; 40 | const int SUBMENU_SETTINGS_RADIO_ENABLED = 2; 41 | const int SUBMENU_SETTINGS_CHANNEL = 2; 42 | const int SUBMENU_SETTINGS_BRIGHTNESS = 3; 43 | 44 | 45 | void init(); 46 | void setMenu(int menuItemSelected); 47 | void showMenu(); 48 | void showFooter(bool trigger, bool triggerHold, bool focus, bool focusHold, bool waiting, bool input); 49 | void showMenuContent(); 50 | bool handleButtons(int forceSync=-1); 51 | void update(bool refresh, bool refreshFooter, bool trigger, bool triggerHold, bool focus, bool focusHold, bool waiting, bool input); 52 | void displayTimeButton(unsigned int x, unsigned int y, unsigned int width, unsigned int height, const char* label, unsigned int valueMs, bool selected=false, bool editing=false, int editingCursor=0); 53 | void displayTime(unsigned int x, unsigned int y, const char* label, unsigned int valueMs, bool selected=false, bool editing=false, int editingCursor=0, OLED::Alignment alignment=OLED::Alignment::LEFT, bool displayFrac=true); 54 | void incrementTimeButton(unsigned int& valueMs); 55 | void decrementTimeButton(unsigned int& valueMs); 56 | void displayIntButton(unsigned int x, unsigned int y, unsigned int width, unsigned int height, const char* label, const char* labelUnit, unsigned int value, unsigned int length, bool selected, bool editing, int editingCursor); 57 | void incrementIntButton(int& value, unsigned int length); 58 | void decrementIntButton(int& value, unsigned int length, int min=0); 59 | void showExitScreen(); 60 | void updateBrightness(); 61 | void copyShadowContext(); 62 | 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/adc.h: -------------------------------------------------------------------------------- 1 | #ifndef _ADC_H_ 2 | #define _ADC_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | #include "error.h" 7 | 8 | // Analog to Digital Converter 9 | // This module is used to measure an analog voltage on a pin 10 | namespace ADC { 11 | 12 | // Peripheral memory space base address 13 | const uint32_t ADC_BASE = 0x40038000; 14 | 15 | // Registers addresses 16 | const uint32_t OFFSET_CR = 0x000; // Control Register 17 | const uint32_t OFFSET_CFG = 0x004; // Configuration Register 18 | const uint32_t OFFSET_SR = 0x008; // Status Register 19 | const uint32_t OFFSET_SCR = 0x00C; // Status Clear Register 20 | const uint32_t OFFSET_SEQCFG = 0x014; // Sequencer Configuration Register 21 | const uint32_t OFFSET_CDMA = 0x018; // Configuration Direct Memory Access Register 22 | const uint32_t OFFSET_TIM = 0x01C; // Timing Configuration Register 23 | const uint32_t OFFSET_ITIMER = 0x020; // Internal Timer Register 24 | const uint32_t OFFSET_WCFG = 0x024; // Window Monitor Configuration Register 25 | const uint32_t OFFSET_WTH = 0x028; // Window Monitor Threshold Configuration Register 26 | const uint32_t OFFSET_LCV = 0x02C; // Sequencer Last Converted Value Register 27 | const uint32_t OFFSET_IER = 0x030; // Interrupt Enable Register 28 | const uint32_t OFFSET_IDR = 0x034; // Interrupt Disable Register 29 | const uint32_t OFFSET_IMR = 0x038; // Interrupt Mask Register 30 | const uint32_t OFFSET_CALIB = 0x03C; // Calibration Register 31 | 32 | // Registers fields 33 | const uint32_t CR_SWRST = 0; 34 | const uint32_t CR_TSTOP = 1; 35 | const uint32_t CR_TSTART = 2; 36 | const uint32_t CR_STRIG = 3; 37 | const uint32_t CR_REFBUFEN = 4; 38 | const uint32_t CR_REFBUFDIS = 5; 39 | const uint32_t CR_EN = 8; 40 | const uint32_t CR_DIS = 9; 41 | const uint32_t CR_BGREQEN = 10; 42 | const uint32_t CR_BGREQDIS = 11; 43 | const uint32_t CFG_REFSEL = 1; 44 | const uint32_t CFG_SPEED = 4; 45 | const uint32_t CFG_CLKSEL = 6; 46 | const uint32_t CFG_PRESCAL = 8; 47 | const uint32_t SR_SEOC = 0; 48 | const uint32_t SR_EN = 24; 49 | const uint32_t SR_TBUSY = 25; 50 | const uint32_t SR_SBUSY = 26; 51 | const uint32_t SR_CBUSY = 27; 52 | const uint32_t SR_REFBUF = 28; 53 | const uint32_t SEQCFG_HWLA = 0; 54 | const uint32_t SEQCFG_BIPOLAR = 2; 55 | const uint32_t SEQCFG_GAIN = 4; 56 | const uint32_t SEQCFG_GCOMP = 7; 57 | const uint32_t SEQCFG_TRGSEL = 8; 58 | const uint32_t SEQCFG_RES = 12; 59 | const uint32_t SEQCFG_INTERNAL = 14; 60 | const uint32_t SEQCFG_MUXPOS = 16; 61 | const uint32_t SEQCFG_MUXNEG = 20; 62 | const uint32_t SEQCFG_ZOOMRANGE = 28; 63 | 64 | 65 | using Channel = uint8_t; 66 | 67 | enum class AnalogReference { 68 | INTERNAL_1V = 0b000, 69 | VCC_0625 = 0b001, // VCC * 0.625 70 | EXTERNAL_REFERENCE = 0b010, 71 | DAC_VOUT = 0b011, 72 | VCC_OVER_2 = 0b100, // VCC / 2 73 | }; 74 | 75 | enum class Gain { 76 | X1 = 0b000, 77 | X2 = 0b001, 78 | X4 = 0b010, 79 | X8 = 0b011, 80 | X16 = 0b100, 81 | X32 = 0b101, 82 | X64 = 0b110, 83 | X05 = 0b111, // divided by 2 84 | }; 85 | 86 | 87 | // Module API 88 | void init(AnalogReference analogReference=AnalogReference::VCC_OVER_2, int vref=3300); 89 | void enable(Channel channel); 90 | void disable(Channel channel); 91 | uint16_t readRaw(Channel channel, Gain gain=Gain::X05, Channel relativeTo=0xFF); 92 | int read(Channel channel, Gain gain=Gain::X05, Channel relativeTo=0xFF); 93 | void setPin(Channel channel, GPIO::Pin pin); 94 | 95 | } 96 | 97 | 98 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/startup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Sections provided by the linker script. See common.ld. 4 | // Note that SECTION_TEXT_START is not a pointer to the start of the .text section, 5 | // it *is* the start of the section (the first byte). The address is &SECTION_TEXT_START. 6 | // The same applies for the other symbols. 7 | extern uint32_t SECTION_TEXT_START; 8 | extern uint32_t SECTION_TEXT_END; 9 | extern uint32_t SECTION_DATA_START; 10 | extern uint32_t SECTION_RELOCATE_START; 11 | extern uint32_t SECTION_RELOCATE_END; 12 | extern uint32_t SECTION_BSS_START; 13 | extern uint32_t SECTION_BSS_END; 14 | extern uint32_t SECTION_STACK_START; 15 | extern uint32_t SECTION_STACK_END; 16 | 17 | // main() is *declared* here but should be *defined* by the user 18 | int main(); 19 | 20 | // Initialization function for the libc standard library. 21 | // It takes cares of tasks such as calling constructors for global variables (objects). 22 | extern "C" void __libc_init_array(void); 23 | 24 | // Reset handler, called when the microcontroller is started 25 | void ResetHandler(void) { 26 | // Copy data from flash to RAM. This includes things such as raw character strings and global 27 | // variables initialized to a non-zero value. 28 | const int SECTION_RELOCATE_LENGTH = &SECTION_RELOCATE_END - &SECTION_RELOCATE_START; // number of 4-bytes words 29 | for (int i = 0; i < SECTION_RELOCATE_LENGTH; i++) { 30 | *(&SECTION_RELOCATE_START + i) = *(&SECTION_DATA_START + i); 31 | } 32 | 33 | // The BSS is the segment containing all global variables initialized to 0. 34 | // It is not stored in the program in flash to save space, and must therefore be 35 | // initialized at runtime. 36 | const int SECTION_BSS_LENGTH = &SECTION_BSS_END - &SECTION_BSS_START; // number of 4-bytes words 37 | for (int i = 0; i < SECTION_BSS_LENGTH; i++) { 38 | *(&SECTION_BSS_START + i) = 0; 39 | } 40 | 41 | // Initialize the standard library 42 | __libc_init_array(); 43 | 44 | // Call the main function defined by the user 45 | main(); 46 | 47 | // The main shouldn't return, but if it does, loop indefinitely here 48 | // to prevent the CPU from executing data beyond the end of the handler 49 | while (true); 50 | } 51 | 52 | // Default dummy handlers for the other exceptions. The library will override them in Core::init(). 53 | 54 | void NMIHandler() { 55 | while (true); 56 | } 57 | 58 | void HardFaultHandler() { 59 | while (true); 60 | } 61 | 62 | void MemManageHandler() { 63 | while (true); 64 | } 65 | 66 | void BusFaultHandler() { 67 | while (true); 68 | } 69 | 70 | void UsageFaultHandler() { 71 | while (true); 72 | } 73 | 74 | void SVCHandler() { 75 | while (true); 76 | } 77 | 78 | void DebugMonHandler() { 79 | while (true); 80 | } 81 | 82 | void PendSVHandler() { 83 | while (true); 84 | } 85 | 86 | void SysTickHandler() { 87 | while (true); 88 | } 89 | 90 | // Vector of pointers to exception handlers, loaded by the linker script at the beginning of the flash 91 | // See ARMv7-M Architecture Reference Manual, B1.5.2 "Exception number definition", page 581 92 | __attribute__ ((section(".vectors"))) 93 | uint32_t exceptionVector[] = { 94 | (uint32_t)&SECTION_STACK_END, 95 | (uint32_t)ResetHandler, 96 | (uint32_t)NMIHandler, 97 | (uint32_t)HardFaultHandler, 98 | (uint32_t)MemManageHandler, 99 | (uint32_t)BusFaultHandler, 100 | (uint32_t)UsageFaultHandler, 101 | (uint32_t)nullptr, 102 | (uint32_t)nullptr, 103 | (uint32_t)nullptr, 104 | (uint32_t)nullptr, 105 | (uint32_t)SVCHandler, 106 | (uint32_t)DebugMonHandler, 107 | (uint32_t)nullptr, 108 | (uint32_t)PendSVHandler, 109 | (uint32_t)SysTickHandler, 110 | }; -------------------------------------------------------------------------------- /sync.cpp: -------------------------------------------------------------------------------- 1 | #include "sync.h" 2 | #include 3 | #include "gui.h" 4 | #include "pins.h" 5 | #include "context.h" 6 | #include "drivers/lora/lora.h" 7 | #include 8 | #include 9 | 10 | namespace Sync { 11 | 12 | const int BUFFER_RX_SIZE = Sync::HEADER_SIZE + Sync::MAX_PAYLOAD_SIZE; 13 | uint8_t _rxBuffer[BUFFER_RX_SIZE]; 14 | int _rxSize = 0; 15 | bool _commandAvailable = false; 16 | bool _rxEnabled = false; 17 | int _rssi = -137; 18 | 19 | bool init() { 20 | LoRa::setPin(LoRa::PinFunction::RESET, PIN_LORA_RESET); 21 | SPI::setPin(static_cast(static_cast(SPI::PinFunction::CS0) + static_cast(SPI_SLAVE_LORA)), PIN_LORA_CS); 22 | if (!LoRa::init(SPI_SLAVE_LORA, LORA_FREQUENCY)) { 23 | return false; 24 | } 25 | LoRa::setTxPower(14); // dBm 26 | LoRa::setSpreadingFactor(8); 27 | LoRa::setCodingRate(LoRa::CodingRate::RATE_4_8); 28 | LoRa::setBandwidth(LoRa::Bandwidth::BW_125kHz); 29 | LoRa::setExplicitHeader(true); 30 | if (Context::_radio != GUI::SUBMENU_SETTINGS_RADIO_DISABLED) { 31 | LoRa::enableRx(); 32 | _rxEnabled = true; 33 | } 34 | return true; 35 | } 36 | 37 | bool commandAvailable() { 38 | // Enable or disable the receiver according to the current setting 39 | if (_rxEnabled && Context::_radio == GUI::SUBMENU_SETTINGS_RADIO_DISABLED) { 40 | LoRa::disableRx(); 41 | _rxEnabled = false; 42 | } else if (!_rxEnabled && Context::_radio != GUI::SUBMENU_SETTINGS_RADIO_DISABLED) { 43 | LoRa::enableRx(); 44 | _rxEnabled = true; 45 | } 46 | 47 | // Check if some data has been received in the LoRa's FIFO 48 | if (Context::_radio != GUI::SUBMENU_SETTINGS_RADIO_DISABLED && LoRa::rxAvailable()) { 49 | // Retreive this data 50 | uint8_t rxBuffer2[BUFFER_RX_SIZE]; 51 | int rxSize2 = LoRa::rx(rxBuffer2, BUFFER_RX_SIZE); 52 | // Check that this looks like a valid frame on the same channel 53 | if (rxSize2 >= HEADER_SIZE && rxBuffer2[HEADER_PREAMBLE] == SYNC_PREAMBLE && rxBuffer2[HEADER_CHANNEL] == Context::_syncChannel) { 54 | // Copy the frame into the main buffer 55 | memcpy(_rxBuffer, rxBuffer2, rxSize2); 56 | _rxSize = rxSize2; 57 | _commandAvailable = true; 58 | } 59 | 60 | _rssi = LoRa::lastPacketRSSI(); 61 | } 62 | return _commandAvailable; 63 | } 64 | 65 | uint8_t getCommand() { 66 | _commandAvailable = false; 67 | if (_rxSize >= HEADER_SIZE) { 68 | return _rxBuffer[HEADER_COMMAND]; 69 | } 70 | return 0xFF; 71 | } 72 | 73 | int getRSSI() { 74 | return _rssi; 75 | } 76 | 77 | int getPayload(uint8_t* buffer) { 78 | _commandAvailable = false; 79 | int payloadSize = _rxSize - HEADER_SIZE; 80 | memcpy(buffer, _rxBuffer + HEADER_SIZE, payloadSize); 81 | return payloadSize; 82 | } 83 | 84 | void send(uint8_t command, uint8_t* payload, int payloadSize) { 85 | if (Context::_radio == GUI::SUBMENU_SETTINGS_RADIO_ENABLED) { 86 | if (payloadSize > MAX_PAYLOAD_SIZE) { 87 | payloadSize = MAX_PAYLOAD_SIZE; 88 | } 89 | uint8_t buffer[HEADER_SIZE + MAX_PAYLOAD_SIZE]; 90 | buffer[HEADER_PREAMBLE] = SYNC_PREAMBLE; 91 | buffer[HEADER_CHANNEL] = Context::_syncChannel; 92 | buffer[HEADER_COMMAND] = command; 93 | if (payloadSize > 0 && payload != nullptr) { 94 | memcpy(buffer + HEADER_SIZE, payload, payloadSize); 95 | } 96 | LoRa::tx(buffer, HEADER_SIZE + payloadSize); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/bpm.h: -------------------------------------------------------------------------------- 1 | #ifndef _BPM_H_ 2 | #define _BPM_H_ 3 | 4 | #include 5 | #include "core.h" 6 | 7 | // Backup Power Manager 8 | // This module manages power-saving features 9 | // TODO : finish this module 10 | namespace BPM { 11 | 12 | // Peripheral memory space base address 13 | const uint32_t BASE = 0x400F0000; 14 | 15 | 16 | // Registers addresses 17 | const uint32_t OFFSET_IER = 0x000; // Interrupt Enable Register 18 | const uint32_t OFFSET_IDR = 0x004; // Interrupt Disable Register 19 | const uint32_t OFFSET_IMR = 0x008; // Interrupt Mask Register 20 | const uint32_t OFFSET_ISR = 0x00C; // Interrupt Status Register 21 | const uint32_t OFFSET_ICR = 0x010; // Interrupt Clear Register 22 | const uint32_t OFFSET_SR = 0x014; // Status Register 23 | const uint32_t OFFSET_UNLOCK = 0x018; // Unlock Register 24 | const uint32_t OFFSET_PMCON = 0x01C; // Power Mode Control Register 25 | const uint32_t OFFSET_BKUPWCAUSE = 0x028; // Backup Wake up Cause Register 26 | const uint32_t OFFSET_BKUPWEN = 0x02C; // Backup Wake up Enable Register 27 | const uint32_t OFFSET_BKUPPMUX = 0x030; // Backup Pin Muxing Register 28 | const uint32_t OFFSET_IORET = 0x034; // Input Output Retention Register 29 | 30 | 31 | // Subregisters 32 | const uint32_t SR_PSOK = 0; 33 | const uint32_t SR_AE = 1; 34 | const uint32_t UNLOCK_ADDR = 0; 35 | const uint32_t UNLOCK_KEY = 0xAA << 24; 36 | const uint32_t PMCON_PS = 0; 37 | const uint32_t PMCON_PSCREQ = 2; 38 | const uint32_t PMCON_PSCM = 3; // Undocumented bit : set to 1 to make a no-halt change 39 | const uint32_t PMCON_BKUP = 8; 40 | const uint32_t PMCON_RET = 9; 41 | const uint32_t PMCON_SLEEP = 12; 42 | const uint32_t PMCON_CK32S = 16; 43 | const uint32_t PMCON_FASTWKUP = 24; 44 | 45 | // Error codes 46 | const Error::Code ERR_UNKNOWN_BACKUP_WAKEUP_CAUSE = 0x0001; 47 | 48 | // Constants 49 | enum class PowerScaling { 50 | PS0 = 0, 51 | PS1 = 1, 52 | PS2 = 2 53 | }; 54 | 55 | enum class BackupWakeUpCause { 56 | EIC = 0, 57 | AST = 1, 58 | WDT = 2, 59 | BOD33 = 3, 60 | BOD18 = 4, 61 | PICOUART = 5, 62 | }; 63 | 64 | // Some peripherals can wake up the chip from backup mode 65 | // See enableBackupWakeUpSource() for more details 66 | enum class BackupWakeUpSource { 67 | EIC = 0, 68 | AST = 1, 69 | WDT = 2, 70 | BOD33 = 3, 71 | BOD18 = 4, 72 | PICOUART = 5, 73 | }; 74 | 75 | // Source for the reference 32KHz (and 1KHz) clocks, 76 | // used by the AST among others 77 | enum class CLK32KSource { 78 | OSC32K, // External crystal 79 | RC32K, // Internal RC 80 | }; 81 | 82 | const int N_INTERRUPTS = 1; 83 | enum class Interrupt { 84 | PSOK = 0, 85 | }; 86 | 87 | 88 | // Module API 89 | 90 | // Power scaling 91 | void setPowerScaling(PowerScaling ps); 92 | PowerScaling currentPowerScaling(); 93 | 94 | // Power save modes 95 | void setSleepMode(Core::SleepMode mode); 96 | BackupWakeUpCause backupWakeUpCause(); 97 | void enableBackupWakeUpSource(BackupWakeUpSource src); 98 | void disableBackupWakeUpSource(BackupWakeUpSource src); 99 | void disableBackupWakeUpSources(); 100 | void enableBackupPin(unsigned int eicChannel); 101 | void disableBackupPin(unsigned int eicChannel); 102 | 103 | // 32KHz clock selection 104 | void set32KHzClockSource(CLK32KSource source); 105 | 106 | // Interrupts 107 | void enableInterrupt(void (*handler)(), Interrupt interrupt=Interrupt::PSOK); 108 | void disableInterrupt(Interrupt interrupt=Interrupt::PSOK); 109 | 110 | } 111 | 112 | 113 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/bscif.h: -------------------------------------------------------------------------------- 1 | #ifndef _BSCIF_H_ 2 | #define _BSCIF_H_ 3 | 4 | #include 5 | 6 | // Backup System Control Interface 7 | // This module manages low-power clocks, the voltage regulator and 8 | // some general-purpose backup data registers 9 | namespace BSCIF { 10 | 11 | // Peripheral memory space base address 12 | const uint32_t BSCIF_BASE = 0x400F0400; 13 | 14 | // Registers addresses 15 | const uint32_t OFFSET_IER = 0x0000; // Interrupt Enable Register 16 | const uint32_t OFFSET_IDR = 0x0004; // Interrupt Disable Register 17 | const uint32_t OFFSET_IMR = 0x0008; // Interrupt Mask Register 18 | const uint32_t OFFSET_ISR = 0x000C; // Interrupt Status Register 19 | const uint32_t OFFSET_ICR = 0x0010; // Interrupt Clear Register 20 | const uint32_t OFFSET_PCLKSR = 0x0014; // Power and Clocks Status Register 21 | const uint32_t OFFSET_UNLOCK = 0x0018; // Unlock Register 22 | const uint32_t OFFSET_CSCR = 0x001C; // Chip Specific Configuration Register 23 | const uint32_t OFFSET_OSCCTRL32 = 0x0020; // Oscillator 32 Control Register 24 | const uint32_t OFFSET_RC32KCR = 0x0024; // 32kHz RC Oscillator Control Register 25 | const uint32_t OFFSET_RC32KTUNE = 0x0028; // 32kHz RC Oscillator Tuning Register 26 | const uint32_t OFFSET_BOD33CTRL = 0x002C; // BOD33 Control Register 27 | const uint32_t OFFSET_BOD33LEVEL = 0x0030; // BOD33 Level Register 28 | const uint32_t OFFSET_BOD33SAMPLING = 0x0034; // BOD33 Sampling Control Register 29 | const uint32_t OFFSET_BOD18CTRL = 0x0038; // BOD18 Control Register 30 | const uint32_t OFFSET_BOD18LEVEL = 0x003C; // BOD18 Level Register 31 | const uint32_t OFFSET_BOD18SAMPLING = 0x0040; // BOD18 Sampling Control Register 32 | const uint32_t OFFSET_VREGCR = 0x0044; // Voltage Regulator Configuration Register 33 | const uint32_t OFFSET_RC1MCR = 0x0048; // 1MHz RC Clock Configuration Register 34 | const uint32_t OFFSET_BGCTRL = 0x0060; // Bandgap Control Register 35 | const uint32_t OFFSET_BGSR = 0x0064; // Bandgap Status Register 36 | const uint32_t OFFSET_BR = 0x0078; // Backup register 37 | 38 | // Subregisters 39 | const uint32_t PCLKSR_OSC32RDY = 0; 40 | const uint32_t PCLKSR_RC32KRDY = 1; 41 | const uint32_t PCLKSR_RC32KLOCK = 2; 42 | const uint32_t PCLKSR_RC32KREFE = 3; 43 | const uint32_t PCLKSR_RC32SAT = 4; 44 | const uint32_t PCLKSR_BOD33DET = 5; 45 | const uint32_t PCLKSR_BOD18DET = 6; 46 | const uint32_t PCLKSR_BOD33SYNRDY = 7; 47 | const uint32_t PCLKSR_BOD18SYNRDY = 8; 48 | const uint32_t PCLKSR_SSWRDY = 9; 49 | const uint32_t PCLKSR_VREGOK = 10; 50 | const uint32_t PCLKSR_RC1MRDY = 11; 51 | const uint32_t PCLKSR_LPBGRDY = 12; 52 | const uint32_t OSCCTRL32_OSC32EN = 0; 53 | const uint32_t OSCCTRL32_EN32K = 2; 54 | const uint32_t OSCCTRL32_EN1K = 3; 55 | const uint32_t OSCCTRL32_MODE = 8; 56 | const uint32_t OSCCTRL32_SELCURR = 12; 57 | const uint32_t OSCCTRL32_STARTUP = 16; 58 | const uint32_t RC32KCR_EN = 0; 59 | const uint32_t RC32KCR_TCEN = 1; 60 | const uint32_t RC32KCR_EN32K = 2; 61 | const uint32_t RC32KCR_EN1K = 3; 62 | const uint32_t RC32KCR_MODE = 4; 63 | const uint32_t RC32KCR_REF = 5; 64 | const uint32_t RC32KCR_FCD = 7; 65 | const uint32_t RC1MCR_CLKOEN = 0; 66 | 67 | // Constants 68 | const uint32_t UNLOCK_KEY = 0xAA << 24; 69 | 70 | 71 | // Module API 72 | void enableOSC32K(); 73 | unsigned long getOSC32KFrequency(); 74 | void enableRC32K(); 75 | unsigned long getRC32KFrequency(); 76 | void enableRC1M(); 77 | unsigned long getRC1MFrequency(); 78 | void storeBackupData(int register, uint32_t data); 79 | uint32_t readBackupData(int register); 80 | 81 | } 82 | 83 | 84 | #endif -------------------------------------------------------------------------------- /libtungsten/usbcom/usbcom.py: -------------------------------------------------------------------------------- 1 | import usb.core, usb.util 2 | import threading 3 | 4 | class USBCom: 5 | OUT = 0 6 | IN = 1 7 | 8 | REQ_BOOTLOADER = 0x00 9 | REQ_CONNECT = 0x01 10 | REQ_DISCONNECT = 0x02 11 | 12 | def __init__(self): 13 | self.connected = False 14 | self.connection_error = False 15 | self.connection_error_message = "" 16 | 17 | self._dev = None 18 | self._ep_in = None 19 | self._ep_out = None 20 | 21 | self._read_handler = None 22 | self._thread_usb = None 23 | 24 | def connect(self, read_handler): 25 | # Reset state 26 | if self.connected and not self.connection_error: 27 | self.disconnect() 28 | self.connected = False 29 | self.connection_error = False 30 | self.connection_error_message = "" 31 | 32 | # Look for an USB device with matching ids 33 | self._dev = usb.core.find(idVendor=0x03eb, idProduct=0xcabd); 34 | if self._dev is None: 35 | self.connection_error = True 36 | self.connection_error_message = "Device not found" 37 | for listener in self.listeners: 38 | listener._on_connection_status(False, self.connection_error_message) 39 | return False 40 | 41 | # Configure the device 42 | self._dev.set_configuration() 43 | cfg = self._dev.get_active_configuration() 44 | intf = cfg[(0, 0)] 45 | 46 | # Find the IN and OUT endpoints 47 | self._ep_in = usb.util.find_descriptor(intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN) 48 | self._ep_in = usb.util.find_descriptor(intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN) 49 | self._ep_out = usb.util.find_descriptor(intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT) 50 | assert self._ep_in is not None 51 | assert self._ep_out is not None 52 | 53 | # Connected 54 | self.connected = True 55 | self._send_request_internal(USBCom.REQ_CONNECT) 56 | 57 | # Start the read thread 58 | self._read_handler = read_handler 59 | self._thread_usb = threading.Thread(target=self._usb_handler) 60 | self._thread_usb.daemon = True 61 | self._thread_usb.start() 62 | 63 | return True 64 | 65 | def disconnect(self): 66 | if self.connected and not self.connection_error: 67 | self._send_request_internal(USBCom.REQ_DISCONNECT) 68 | self.connected = False 69 | self._thread_usb.join() 70 | 71 | def _send_request_internal(self, request, value=0, index=0, direction=OUT, payload=None): 72 | if self.connected and not self.connection_error: 73 | bmRequestType = direction << 7 | 2 << 5 74 | self._dev.ctrl_transfer(bmRequestType, request, value, index, payload) 75 | 76 | def send_request(self, request, value=0, index=0, direction=OUT, payload=None): 77 | return self._send_request_internal(request | 0x80, value, index, direction, payload) 78 | 79 | def write(self, data): 80 | if self.connected and not self.connection_error: 81 | self._ep_out.write(data) 82 | 83 | def _usb_handler(self): 84 | while self.connected and not self.connection_error: 85 | try: 86 | buff = self._ep_in.read(64, 100) 87 | except usb.core.USBError as e: 88 | if e.errno != 110: 89 | self.connected = False 90 | self.connection_error = True 91 | self.connection_error_message = str(e) 92 | print("") 93 | print("USB error " + str(e.errno) + " : " + e.strerror) 94 | return 95 | else: 96 | if len(buff) > 0: 97 | self._read_handler(buff) -------------------------------------------------------------------------------- /libtungsten/sam4l/dma.h: -------------------------------------------------------------------------------- 1 | #ifndef _DMA_H_ 2 | #define _DMA_H_ 3 | 4 | #include 5 | #include "error.h" 6 | 7 | // Direct Memory Access 8 | // This module is able to automatically copy data between RAM and peripherals, 9 | // without CPU intervention 10 | namespace DMA { 11 | 12 | // Peripheral memory space base address 13 | const uint32_t BASE = 0x400A2000; 14 | const uint32_t CHANNEL_REG_SIZE = 0x40; 15 | 16 | // Registers addresses 17 | const uint32_t OFFSET_MAR = 0x000; // Memory Address Register 18 | const uint32_t OFFSET_PSR = 0x004; // Peripheral Select Register 19 | const uint32_t OFFSET_TCR = 0x008; // Transfer Counter Register 20 | const uint32_t OFFSET_MARR = 0x00C; // Memory Address Reload Register 21 | const uint32_t OFFSET_TCRR = 0x010; // Transfer Counter Reload Register 22 | const uint32_t OFFSET_CR = 0x014; // Control Register 23 | const uint32_t OFFSET_MR = 0x018; // Mode Register 24 | const uint32_t OFFSET_SR = 0x01C; // Status Register 25 | const uint32_t OFFSET_IER = 0x020; // Interrupt Enable Register 26 | const uint32_t OFFSET_IDR = 0x024; // Interrupt Disable Register 27 | const uint32_t OFFSET_IMR = 0x028; // Interrupt Mask Register 28 | const uint32_t OFFSET_ISR = 0x02C; // Interrupt Status Register 29 | 30 | // Subregisters 31 | const uint8_t MR_SIZE = 0; 32 | const uint8_t MR_ETRIG = 2; 33 | const uint8_t MR_RING = 3; 34 | const uint8_t CR_TEN = 0; 35 | const uint8_t CR_TDIS = 1; 36 | const uint8_t ISR_RCZ = 0; 37 | const uint8_t ISR_TRC = 1; 38 | const uint8_t ISR_TERR = 2; 39 | const uint8_t SR_TEN = 0; 40 | 41 | // Error codes 42 | const Error::Code ERR_NO_CHANNEL_AVAILABLE = 0x0001; 43 | const Error::Code ERR_CHANNEL_NOT_INITIALIZED = 0x0002; 44 | 45 | // Size constants 46 | enum class Size { 47 | BYTE, 48 | HALFWORD, 49 | WORD 50 | }; 51 | 52 | // Interrupts 53 | const int N_INTERRUPTS = 3; 54 | enum class Interrupt { 55 | RELOAD_EMPTY, 56 | TRANSFER_FINISHED, 57 | TRANSFER_ERROR 58 | }; 59 | 60 | // Device constants 61 | enum class Device { 62 | USART0_RX = 0, 63 | USART1_RX = 1, 64 | USART2_RX = 2, 65 | USART3_RX = 3, 66 | SPI_RX = 4, 67 | I2C0_M_RX = 5, 68 | I2C1_M_RX = 6, 69 | I2C2_M_RX = 7, 70 | I2C3_M_RX = 8, 71 | I2C0_S_RX = 9, 72 | I2C1_S_RX = 10, 73 | USART0_TX = 18, 74 | USART1_TX = 19, 75 | USART2_TX = 20, 76 | USART3_TX = 21, 77 | SPI_TX = 22, 78 | I2C0_M_TX = 23, 79 | I2C1_M_TX = 24, 80 | I2C2_M_TX = 25, 81 | I2C3_M_TX = 26, 82 | I2C0_S_TX = 27, 83 | I2C1_S_TX = 28, 84 | DAC = 35 85 | }; 86 | 87 | struct ChannelConfig { 88 | bool started; 89 | bool interruptsEnabled; 90 | }; 91 | 92 | const int N_CHANNELS_MAX = 16; 93 | 94 | // Module API 95 | int newChannel(Device device, Size size, uint32_t address=0x00000000, uint16_t length=0, bool ring=false); 96 | void enableInterrupt(int channel, void (*handler)(), Interrupt interrupt=Interrupt::TRANSFER_FINISHED); 97 | void disableInterrupt(int channel, Interrupt interrupt=Interrupt::TRANSFER_FINISHED); 98 | void setupChannel(int channel, uint32_t address, uint16_t length); 99 | void startChannel(int channel); 100 | void startChannel(int channel, uint32_t address, uint16_t length); 101 | void reloadChannel(int channel, uint32_t address, uint16_t length); 102 | void stopChannel(int channel); 103 | int getCounter(int channel); 104 | bool isEnabled(int channel); 105 | bool isFinished(int channel); 106 | bool isReloadEmpty(int channel); 107 | void enableRing(int channel); 108 | void disableRing(int channel); 109 | 110 | } 111 | 112 | #endif -------------------------------------------------------------------------------- /context.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "gui.h" 3 | #include 4 | 5 | int Context::_menuItemSelected = 0; 6 | int Context::_submenuItemSelected = 0; 7 | bool Context::_editingItem = false; 8 | int Context::_editingItemCursor = 0; 9 | bool Context::_btnOkPressed = false; 10 | bool Context::_submenuFocusHold = false; 11 | bool Context::_submenuTriggerHold = false; 12 | 13 | bool Context::_triggerSync = true; 14 | unsigned int Context::_delayMs = 0; 15 | bool Context::_delaySync = true; 16 | int Context::_intervalNShots = 1; 17 | unsigned int Context::_intervalDelayMs = 1000; 18 | bool Context::_intervalSync = true; 19 | int Context::_inputMode = GUI::SUBMENU_INPUT_MODE_PASSTHROUGH; 20 | bool Context::_inputSync = true; 21 | unsigned int Context::_timingsFocusDurationMs = 0; 22 | unsigned int Context::_timingsTriggerDurationMs = 100; 23 | bool Context::_timingsSync = true; 24 | int Context::_syncChannel = 0; 25 | int Context::_radio = GUI::SUBMENU_SETTINGS_RADIO_ENABLED; 26 | int Context::_brightness = 3; 27 | 28 | Core::Time Context::_tFocus = 0; 29 | Core::Time Context::_tTrigger = 0; 30 | bool Context::_inhibitTriggerHold = false; 31 | bool Context::_skipDelay = false; 32 | int Context::_shotsLeft = 0; 33 | unsigned int Context::_countdown = 0; 34 | 35 | int Context::_vBat = 0; 36 | 37 | unsigned int Context::_shadowDelayMs = 0; 38 | int Context::_shadowIntervalNShots = 1; 39 | unsigned int Context::_shadowIntervalDelayMs = 0; 40 | unsigned int Context::_shadowTimingsFocusDurationMs = 0; 41 | unsigned int Context::_shadowTimingsTriggerDurationMs = 0; 42 | 43 | int Context::_rssi = -137; 44 | Core::Time Context::_tReceivedCommand = 0; 45 | 46 | 47 | void Context::read() { 48 | uint32_t pageBuffer[Flash::FLASH_PAGE_SIZE_WORDS]; 49 | Flash::readUserPage(pageBuffer); 50 | // First two words are reserved 51 | int i = 2; 52 | if (pageBuffer[i] == 0xFFFFFFFF) { 53 | // Empty config, initialize it by saving the default config 54 | save(); 55 | } else { 56 | _triggerSync = static_cast(pageBuffer[i++]); 57 | _delayMs = static_cast(pageBuffer[i++]); 58 | _delaySync = static_cast(pageBuffer[i++]); 59 | _intervalNShots = static_cast(pageBuffer[i++]); 60 | _intervalDelayMs = static_cast(pageBuffer[i++]); 61 | _intervalSync = static_cast(pageBuffer[i++]); 62 | _inputMode = static_cast(pageBuffer[i++]); 63 | _inputSync = static_cast(pageBuffer[i++]); 64 | _timingsFocusDurationMs = static_cast(pageBuffer[i++]); 65 | _timingsTriggerDurationMs = static_cast(pageBuffer[i++]); 66 | _timingsSync = static_cast(pageBuffer[i++]); 67 | _syncChannel = static_cast(pageBuffer[i++]); 68 | _radio = static_cast(pageBuffer[i++]); 69 | _brightness = static_cast(pageBuffer[i++]); 70 | } 71 | } 72 | 73 | void Context::save() { 74 | uint32_t pageBuffer[Flash::FLASH_PAGE_SIZE_WORDS]; 75 | Flash::readUserPage(pageBuffer); 76 | // First two words are reserved 77 | int i = 2; 78 | pageBuffer[i++] = static_cast(_triggerSync); 79 | pageBuffer[i++] = static_cast(_delayMs); 80 | pageBuffer[i++] = static_cast(_delaySync); 81 | pageBuffer[i++] = static_cast(_intervalNShots); 82 | pageBuffer[i++] = static_cast(_intervalDelayMs); 83 | pageBuffer[i++] = static_cast(_intervalSync); 84 | pageBuffer[i++] = static_cast(_inputMode); 85 | pageBuffer[i++] = static_cast(_inputSync); 86 | pageBuffer[i++] = static_cast(_timingsFocusDurationMs); 87 | pageBuffer[i++] = static_cast(_timingsTriggerDurationMs); 88 | pageBuffer[i++] = static_cast(_timingsSync); 89 | pageBuffer[i++] = static_cast(_syncChannel); 90 | pageBuffer[i++] = static_cast(_radio); 91 | pageBuffer[i++] = static_cast(_brightness); 92 | Flash::writeUserPage(pageBuffer); 93 | } 94 | -------------------------------------------------------------------------------- /libtungsten/sam4l/flash.h: -------------------------------------------------------------------------------- 1 | #ifndef _FLASH_H_ 2 | #define _FLASH_H_ 3 | 4 | #include 5 | 6 | // This module gives access to the Flash memory embedded in the chip 7 | namespace Flash { 8 | 9 | // Config registers memory space base address and flash memory base address 10 | const uint32_t FLASH_BASE = 0x400A0000; 11 | const uint32_t FLASH_ARRAY_BASE = 0x00000000; 12 | const uint32_t USER_PAGE_BASE = FLASH_ARRAY_BASE + 0x00800000; 13 | const int FLASH_PAGE_SIZE_BYTES = 512; // bytes 14 | const int FLASH_PAGE_SIZE_WORDS = 128; // words 15 | // N_FLASH_PAGES is a preprocessor word defined in the library Makefile which depend on CHIP_MODEL 16 | const int FLASH_PAGES = N_FLASH_PAGES; // pages 17 | 18 | // Register offsets 19 | const uint32_t OFFSET_FCR = 0x00; // Flash Control Register 20 | const uint32_t OFFSET_FCMD = 0x04; // Flash Command Register 21 | const uint32_t OFFSET_FSR = 0x08; // Flash Status Register 22 | const uint32_t OFFSET_FPR = 0x0C; // Flash Parameter Register 23 | const uint32_t OFFSET_FVR = 0x10; // Flash Version Register 24 | const uint32_t OFFSET_FGPFRHI = 0x14; // Flash General Purpose Fuse Register Hi -- not implemented 25 | const uint32_t OFFSET_FGPFRLO = 0x18; // Flash General Purpose Fuse Register Lo 26 | const uint32_t OFFSET_CTRL = 0x408; // PicoCache Control Register 27 | const uint32_t OFFSET_SR = 0x40C; // PicoCache Status Register 28 | const uint32_t OFFSET_MAINT0 = 0x420; // PicoCache Maintenance Register 0 29 | const uint32_t OFFSET_MAINT1 = 0x424; // PicoCache Maintenance Register 1 30 | const uint32_t OFFSET_MCFG = 0x428; // PicoCache Monitor Configuration Register 31 | const uint32_t OFFSET_MEN = 0x42C; // PicoCache Monitor Enable Register 32 | const uint32_t OFFSET_MCTRL = 0x430; // PicoCache Monitor Control Register 33 | const uint32_t OFFSET_MSR = 0x434; // PicoCache Monitor Status Register 34 | const uint32_t OFFSET_PVR = 0x4FC; // Version Register 35 | 36 | // Constants 37 | const uint32_t FSR_FRDY = 0; 38 | const uint32_t FSR_HSMODE = 6; 39 | const uint32_t FCMD_CMD = 0; 40 | const uint32_t FCMD_CMD_NOP = 0; 41 | const uint32_t FCMD_CMD_WP = 1; 42 | const uint32_t FCMD_CMD_EP = 2; 43 | const uint32_t FCMD_CMD_CPB = 3; 44 | const uint32_t FCMD_CMD_LP = 4; 45 | const uint32_t FCMD_CMD_UP = 5; 46 | const uint32_t FCMD_CMD_EA = 6; 47 | const uint32_t FCMD_CMD_WGPB = 7; 48 | const uint32_t FCMD_CMD_EGPB = 8; 49 | const uint32_t FCMD_CMD_SSB = 9; 50 | const uint32_t FCMD_CMD_PGPFB = 10; 51 | const uint32_t FCMD_CMD_EAGPF = 11; 52 | const uint32_t FCMD_CMD_QPR = 12; 53 | const uint32_t FCMD_CMD_WUP = 13; 54 | const uint32_t FCMD_CMD_EUP = 14; 55 | const uint32_t FCMD_CMD_QPRUP = 15; 56 | const uint32_t FCMD_CMD_HSEN = 16; 57 | const uint32_t FCMD_CMD_HSDIS = 17; 58 | const uint32_t FCMD_PAGEN = 8; 59 | const uint32_t FCMD_KEY = 0xA5 << 24; 60 | 61 | // General-purpose fuses 62 | using Fuse = uint8_t; 63 | const int N_FUSES = 16; 64 | 65 | // These fuses are used by the bootloader and are reserved if the bootloader is enabled 66 | // They need to be defined here for the Core::resetToBootloader() helper function 67 | const Fuse FUSE_BOOTLOADER_FW_READY = 0; 68 | const Fuse FUSE_BOOTLOADER_FORCE = 1; 69 | const Fuse FUSE_BOOTLOADER_SKIP_TIMEOUT = 2; 70 | const int BOOTLOADER_N_RESERVED_FUSES = 3; 71 | 72 | 73 | // Module API 74 | bool isReady(); 75 | uint32_t read(uint32_t address); 76 | void readPage(int page, uint32_t data[]); 77 | void erasePage(int page); 78 | void clearPageBuffer(); 79 | void writePage(int page, const uint32_t data[]); 80 | void readUserPage(uint32_t data[]); 81 | void eraseUserPage(); 82 | void writeUserPage(const uint32_t data[]); 83 | void writeFuse(Fuse fuse, bool state); 84 | bool getFuse(Fuse fuse); 85 | void enableHighSpeedMode(); 86 | void disableHighSpeedMode(); 87 | 88 | } 89 | 90 | 91 | #endif -------------------------------------------------------------------------------- /drivers/oled_ssd1306/oled.h: -------------------------------------------------------------------------------- 1 | #ifndef _OLED_H_ 2 | #define _OLED_H_ 3 | 4 | #include 5 | #include "font.h" 6 | 7 | namespace OLED { 8 | 9 | // Display buffer 10 | const int WIDTH = 128; 11 | const int HEIGHT = 64; 12 | const int N_PAGES = HEIGHT / 8; 13 | const int DISPLAY_BUFFER_SIZE = N_PAGES * WIDTH; 14 | 15 | // Commands 16 | const uint8_t CMD_DISPLAY_OFF = 0xAE; 17 | const uint8_t CMD_DISPLAY_ON = 0xAF; 18 | const uint8_t CMD_DISPLAY_NORMAL = 0xA6; 19 | const uint8_t CMD_DISPLAY_INVERTED = 0xA7; 20 | const uint8_t CMD_CONTRAST = 0x81; 21 | const uint8_t CMD_CHARGE_PUMP = 0x8D; 22 | const uint8_t CMD_ADDRESSING_MODE = 0x20; 23 | const uint8_t CMD_COLUMN_START_END = 0x21; 24 | const uint8_t CMD_PAGE_START_END = 0x22; 25 | const uint8_t CMD_SEGMENT_REMAP_OFF = 0xA0; 26 | const uint8_t CMD_SEGMENT_REMAP_ON = 0xA1; 27 | const uint8_t CMD_COM_SCAN_DIRECTION_NORMAL = 0xC0; 28 | const uint8_t CMD_COM_SCAN_DIRECTION_INVERT = 0xC8; 29 | 30 | enum class Rotation { 31 | R0, 32 | R90, 33 | R180, 34 | R270, 35 | }; 36 | 37 | enum class Alignment { 38 | LEFT, 39 | CENTERED, 40 | RIGHT 41 | }; 42 | 43 | void initScreen(SPI::Peripheral spi, GPIO::Pin pinDC, GPIO::Pin pinRES); 44 | void enable(); 45 | void disable(); 46 | void setContrast(uint8_t contrast); 47 | void sendCommand(uint8_t command); 48 | void refresh(); 49 | void setColorInverted(bool inverted=true); 50 | void clear(); 51 | void clear(unsigned int x, unsigned int y, unsigned int width, unsigned int height); 52 | void setPixel(unsigned int x, unsigned int y, bool on=true); 53 | void rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool on=true); 54 | void resetPixel(unsigned int x, unsigned int y); 55 | void print(char character); 56 | void print(unsigned int x, unsigned int y, char character); 57 | void print(const char* text); 58 | void print(unsigned int x, unsigned int y, const char* text); 59 | void printCentered(unsigned int x, unsigned int y, const char* text); 60 | int charWidth(char c); 61 | int textWidth(const char* text); 62 | void printInt(unsigned int x, unsigned int y, int value, int base=10); 63 | void printInt(int value, int base=10); 64 | void printSmall(char character); 65 | void printSmall(unsigned int x, unsigned int y, char character); 66 | void printSmall(unsigned int x, unsigned int y, const Font::Char5 c); 67 | void printMedium(char character); 68 | void printMedium(unsigned int x, unsigned int y, char character); 69 | void printMedium(unsigned int x, unsigned int y, const Font::Char8 c); 70 | void printLarge(char character); 71 | void printLarge(unsigned int x, unsigned int y, char character); 72 | void printLarge(unsigned int x, unsigned int y, const Font::Char16 c); 73 | void printXLarge(unsigned int x, unsigned int y, const Font::Char32 c); 74 | void printXXLarge(unsigned int x, unsigned int y, const Font::Char64 c); 75 | void progressbar(unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned char percent); 76 | void button(unsigned int x, unsigned int y, unsigned int width, unsigned int height, const char* label, bool selected=false, bool pressed=false, bool arrowLeft=false, bool arrowRight=false); 77 | void checkbox(unsigned int x, unsigned int y, unsigned int width, unsigned int height, const char* label, bool selected, bool pressed, bool checked); 78 | unsigned int cursorX(); 79 | unsigned int cursorY(); 80 | void setCursor(unsigned int x, unsigned int y); 81 | void setCursorX(unsigned int x); 82 | void setCursorY(unsigned int y); 83 | void moveCursor(unsigned int x, unsigned int y); 84 | void moveCursorX(unsigned int x); 85 | void moveCursorY(unsigned int y); 86 | void setSize(Font::Size size); 87 | void setInverted(bool inverted); 88 | void setRotation(Rotation rotation); 89 | unsigned int getFontHeight(); 90 | unsigned int getFontHeight(Font::Size size); 91 | unsigned int getFontWidth(); 92 | unsigned int getFontWidth(Font::Size size); 93 | 94 | } 95 | 96 | #endif -------------------------------------------------------------------------------- /icons/silica_64.pbm: -------------------------------------------------------------------------------- 1 | P1 2 | # Created by GIMP version 2.10.8 PNM plug-in 3 | 64 64 4 | 0000000000000000000000000000000000000000000000000000000000000000000000 5 | 0000000000000000000000000000000000000000000000000000000000000000000000 6 | 0000000000000000000000000000000000000000000000000000000000000000000000 7 | 1111100000000000000000000110000000000000000000000000000011111111100111 8 | 0000000000000000001101000000000000000000000000011110000000000101100000 9 | 0000000000011100100000000000000000000000011000000000000100111000000000 10 | 0000111100010000000000000000000000011100000000001000001100000000000011 11 | 1100001000000000000000000000011110000000001000000110000000000111110000 12 | 0100000000000000000000011111000000010000000011000000001111110000001000 13 | 0000000000000000011111100000010000000000110000001111110000110100000000 14 | 0000000000011111110000010000000000011000011111110111000100000000000000 15 | 0000011111111000100000000000001100010000011000000100000000000000000001 16 | 1111111110100000000000000110011111111000000100000000000000000001111111 17 | 1111000000000000000001111111111000000110000000000000000000111111110110 18 | 0000000000000000111111111000000010000000000000000000111111101111000000 19 | 0000000000011111111000000010000000000000000000111110011111100000000000 20 | 0000001111111000000010000000000000000000111001111111111000000000000000 21 | 0011111100000010000000000000000000110111111111111100000000000000000111 22 | 1100000010000000000000000000111111111111111110000000000000000011110000 23 | 0011000000000000000000011111111111111111000000000000000000110000000100 24 | 0000000000000000001111111111111111110000000000000000011000000100000000 25 | 0000000000000011111111111111111000000000000000001100000100000000000000 26 | 0000000001111111111111111100000000000000000110000100000000000000000000 27 | 0000111111111111111111000000000000000001100100000000000000000000000000 28 | 1111111111111111100000000000000000110110000000000000000000000000011111 29 | 1111111111110000000000000000011110000000000000000000000000001111111111 30 | 1111111000000000000000001110000000000000000000000000000111111111111111 31 | 1110000000000000000011000000000000000000000000000001111111111111111100 32 | 0000000000000001000000000000000000000000000000111111111111111110000000 33 | 0000000011000000000000000000000000000000011111111111111111000000000000 34 | 0011000000000000000000000000000000011111111111111111110000000000010100 35 | 0000000000000000000000000000110000000000111111111111110000010100000000 36 | 0000000000000000000001100100000000000000000000111000010110000000000000 37 | 0000000000000011000100000000000000000000001100100110000000000000000000 38 | 0000000110000010000000000000000000000100100010000000000000000000000000 39 | 1000000010000000000000000000001010100010000000000000000000000001111110 40 | 0001000000000000000000001001000010000000000000000000000000111111111111 41 | 1000000000000000001001100010000000000000000000000000011111110111111111 42 | 1111111000001000110010000000000000000000000000001111101111111111111111 43 | 1111111111110010000000000000000000000000001111101111111111111111111111 44 | 0111111110000000000000000000000000000111011111111111111111111111011111 45 | 1110000000000000000000000000000011011111111111111111111110111111111000 46 | 0000000000000000000000000001111111111111111111111110110000000000000000 47 | 0000000000000000000000000011111111111111111111000000000000000000000000 48 | 0000000000000000000000000000000111111110000000000000000000000000000000 49 | 0000000000000000000000000000000000000000000000000000000000000000000000 50 | 0000000000000000000000000000000000000000000000000000000000000000000000 51 | 0000000000000000000000000000000000000000000000000000000000000000000000 52 | 0000000000000000000000000000000000000000000000000000000000000000000000 53 | 0000000000000000000000000000000000000000000000000000000000000000000000 54 | 0000000000000000000000000000000000000000000000000000000000000000000000 55 | 0000000000000000000000000000000000000000000000000000000000000000000000 56 | 0000000000000000000000000000000000000000000000000000000000000000000000 57 | 0000000000000000000000000000000000000000000000000000000000000000000000 58 | 0000000000000000000000000000000000000000000000000000000000000000000000 59 | 0000000000000000000000000000000000000000000000000000000000000000000000 60 | 0000000000000000000000000000000000000000000000000000000000000000000000 61 | 0000000000000000000000000000000000000000000000000000000000000000000000 62 | 000000000000000000000000000000000000 -------------------------------------------------------------------------------- /drivers/lora/lora.h: -------------------------------------------------------------------------------- 1 | #ifndef _LORA_H_ 2 | #define _LORA_H_ 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace LoRa { 9 | 10 | const uint32_t DEFAULT_FREQUENCY = 868000000L; // 868MHz 11 | const int MAX_TX_LENGTH = 128; 12 | 13 | // Registers 14 | const uint8_t REG_FIFO = 0x00; 15 | const uint8_t REG_OP_MODE = 0x01; 16 | const uint8_t REG_FR_MSB = 0x06; 17 | const uint8_t REG_FR_MID = 0x07; 18 | const uint8_t REG_FR_LSB = 0x08; 19 | const uint8_t REG_PA_CONFIG = 0x09; 20 | const uint8_t REG_FIFO_ADDR_PTR = 0x0D; 21 | const uint8_t REG_FIFO_TX_BASE_ADDR = 0x0E; 22 | const uint8_t REG_FIFO_RX_BASE_ADDR = 0x0F; 23 | const uint8_t REG_FIFO_RX_CURRENT_ADDR = 0x10; 24 | const uint8_t REG_IRQ_FLAGS_MASK = 0x11; 25 | const uint8_t REG_IRQ_FLAGS = 0x12; 26 | const uint8_t REG_FIFO_RX_BYTES_NB = 0x13; 27 | const uint8_t REG_PKT_RSSI_VALUE = 0x1A; 28 | const uint8_t REG_RSSI_VALUE = 0x1B; 29 | const uint8_t REG_MODEM_CONFIG_1 = 0x1D; 30 | const uint8_t REG_MODEM_CONFIG_2 = 0x1E; 31 | const uint8_t REG_PAYLOAD_LENGTH = 0x22; 32 | const uint8_t REG_MODEM_CONFIG_3 = 0x26; 33 | const uint8_t REG_FIFO_RX_BYTE_ADDR = 0x25; 34 | const uint8_t REG_VERSION = 0x42; 35 | const uint8_t REG_PA_DAC = 0x4D; 36 | 37 | // Subregisters 38 | const uint8_t REG_MODEM_CONFIG_1_IMPLICIT_HEADER_MODE = 0; 39 | const uint8_t REG_MODEM_CONFIG_1_CODING_RATE = 1; 40 | const uint8_t REG_MODEM_CONFIG_1_BW = 4; 41 | const uint8_t REG_MODEM_CONFIG_2_RX_PAYLOAD_CRC_ON = 2; 42 | const uint8_t REG_MODEM_CONFIG_2_TX_CONTINUOUS_MODE = 3; 43 | const uint8_t REG_MODEM_CONFIG_2_SPREADING_FACTOR = 4; 44 | const uint8_t REG_MODEM_CONFIG_3_AGC_AUTO_ON = 2; 45 | const uint8_t REG_MODEM_CONFIG_3_MOBILE_NODE = 3; 46 | const uint8_t REG_PA_CONFIG_OUTPUT_POWER = 0; 47 | const uint8_t REG_PA_CONFIG_MAX_POWER = 4; 48 | const uint8_t REG_PA_CONFIG_PA_BOOST = 7; 49 | const uint8_t REG_PA_DAC_DEFAULT = 0x84; 50 | const uint8_t REG_PA_DAC_HIGH = 0x87; 51 | const uint8_t IRQ_CAD_DETECTED = 0; 52 | const uint8_t IRQ_FHSS_CHANGE_CHANNEL = 1; 53 | const uint8_t IRQ_CAD_DONE = 2; 54 | const uint8_t IRQ_TX_DONE = 3; 55 | const uint8_t IRQ_VALID_HEADER = 4; 56 | const uint8_t IRQ_PAYLOAD_CRC_ERROR = 5; 57 | const uint8_t IRQ_RX_DONE = 6; 58 | const uint8_t IRQ_RX_TIMEOUT = 7; 59 | 60 | // Error codes 61 | const int INVALID_HEADER = -1; 62 | const int PAYLOAD_CRC_ERROR = -2; 63 | 64 | // Operating modes 65 | enum class Mode { 66 | SLEEP = 0b000, 67 | STANDBY = 0b001, 68 | FSTX = 0b010, // Frequency synthesis TX 69 | TX = 0b011, 70 | FSRX = 0b100, // Frequency synthesis RX 71 | RX_CONTINUOUS = 0b101, 72 | RX_SINGLE = 0b110, 73 | CAD = 0b111, // Channel activity detection 74 | }; 75 | 76 | // Coding rate 77 | enum class CodingRate { 78 | RATE_4_5 = 1, 79 | RATE_4_6 = 2, 80 | RATE_4_7 = 3, 81 | RATE_4_8 = 4, 82 | }; 83 | 84 | // Bandwidth 85 | enum class Bandwidth { 86 | BW_7_8kHz, 87 | BW_10_4kHz, 88 | BW_15_6kHz, 89 | BW_20_8kHz, 90 | BW_31_3kHz, 91 | BW_41_7kHz, 92 | BW_62_5kHz, 93 | BW_125kHz, 94 | BW_250kHz, 95 | BW_500kHz 96 | }; 97 | 98 | enum class PinFunction { 99 | RESET 100 | }; 101 | 102 | 103 | void setPin(PinFunction pinFunction, GPIO::Pin pin); 104 | void disable(); 105 | bool init(SPI::Peripheral slave, uint32_t frequency=DEFAULT_FREQUENCY); 106 | void setMode(Mode mode); 107 | void setFrequency(uint32_t frequency); 108 | void setTxPower(int dBm); 109 | void setSpreadingFactor(int spreadingFactor); 110 | void setCodingRate(CodingRate codingRate); 111 | void setBandwidth(Bandwidth bandwidth); 112 | void setExplicitHeader(bool explicitHeaderEnabled); 113 | void tx(uint8_t* payload, unsigned int length); 114 | void enableRx(); 115 | void disableRx(); 116 | bool rxAvailable(); 117 | int rx(uint8_t* buffer, unsigned int length); 118 | int lastPacketRSSI(); 119 | int currentRSSI(); 120 | uint8_t readRegister(uint8_t reg); 121 | void writeRegister(uint8_t reg, uint8_t value); 122 | 123 | } 124 | 125 | #endif -------------------------------------------------------------------------------- /libtungsten/carbide/carbide.cpp: -------------------------------------------------------------------------------- 1 | #include "carbide.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Carbide { 11 | 12 | // USB request codes 13 | enum class Request { 14 | START_BOOTLOADER, 15 | CONNECT, 16 | STATUS, 17 | WRITE, 18 | GET_ERROR, 19 | }; 20 | 21 | // Handler called when a CONTROL packet is sent over USB 22 | int usbControlHandler(USB::SetupPacket &lastSetupPacket, uint8_t* data, int size) { 23 | Request request = static_cast(lastSetupPacket.bRequest); 24 | if (request == Request::START_BOOTLOADER) { 25 | lastSetupPacket.handled = true; 26 | Core::resetToBootloader(10); 27 | } 28 | return 0; 29 | } 30 | 31 | // Handler called when an error of Warning level is triggered 32 | void warningHandler(Error::Module module, int userModule, Error::Code code) { 33 | // Blink the red LED three times and resume operation 34 | setLedR(false); 35 | Core::sleep(100); 36 | setLedR(); 37 | Core::sleep(100); 38 | setLedR(false); 39 | Core::sleep(100); 40 | setLedR(); 41 | Core::sleep(100); 42 | setLedR(false); 43 | Core::sleep(100); 44 | } 45 | 46 | // Handler called when an error of Critical level is triggered 47 | void criticalHandler(Error::Module module, int userModule, Error::Code code) { 48 | // Stop the execution and blink the red LED rapidly 49 | while (1) { 50 | setLedR(); 51 | Core::sleep(100); 52 | setLedR(false); 53 | Core::sleep(100); 54 | } 55 | } 56 | 57 | void init(bool autoBootloaderReset) { 58 | // Init the microcontroller on the default 12MHz clock 59 | Core::init(); 60 | setCPUFrequency(CPUFreq::FREQ_12MHZ); 61 | 62 | if (autoBootloaderReset) { 63 | // Init the USB port start the bootloader when requested 64 | USB::initDevice(); 65 | USB::setControlHandler(usbControlHandler); 66 | } 67 | 68 | // Init the leds and button 69 | initLeds(); 70 | initButton(); 71 | 72 | // Set error handlers 73 | Error::setHandler(Error::Severity::WARNING, warningHandler); 74 | Error::setHandler(Error::Severity::CRITICAL, criticalHandler); 75 | } 76 | 77 | void setCPUFrequency(CPUFreq frequency) { 78 | switch (frequency) { 79 | case CPUFreq::FREQ_4MHZ: 80 | SCIF::enableRCFAST(SCIF::RCFASTFrequency::RCFAST_4MHZ); 81 | PM::setMainClockSource(PM::MainClockSource::RCFAST); 82 | break; 83 | 84 | case CPUFreq::FREQ_8MHZ: 85 | SCIF::enableRCFAST(SCIF::RCFASTFrequency::RCFAST_8MHZ); 86 | PM::setMainClockSource(PM::MainClockSource::RCFAST); 87 | break; 88 | 89 | case CPUFreq::FREQ_12MHZ: 90 | SCIF::enableRCFAST(SCIF::RCFASTFrequency::RCFAST_12MHZ); 91 | PM::setMainClockSource(PM::MainClockSource::RCFAST); 92 | break; 93 | 94 | case CPUFreq::FREQ_24MHZ: 95 | SCIF::enableDFLL(24000000UL); 96 | PM::setMainClockSource(PM::MainClockSource::DFLL); 97 | break; 98 | 99 | case CPUFreq::FREQ_36MHZ: 100 | SCIF::enableDFLL(36000000UL); 101 | PM::setMainClockSource(PM::MainClockSource::DFLL); 102 | break; 103 | 104 | case CPUFreq::FREQ_48MHZ: 105 | BPM::setPowerScaling(BPM::PowerScaling::PS2); 106 | SCIF::enableDFLL(48000000UL); 107 | PM::setMainClockSource(PM::MainClockSource::DFLL); 108 | break; 109 | } 110 | 111 | // Wait 100ms to make sure the clocks have stabilized 112 | Core::sleep(100); 113 | } 114 | 115 | // Enable an handler to be called by interrupt when the button the button is 116 | // either pressed or realeased 117 | void onButtonPressed(void (*handler)(), bool released) { 118 | GPIO::enableInterrupt(PIN_BUTTON, handler, (released ? GPIO::Trigger::RISING : GPIO::Trigger::FALLING)); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /libtungsten/sam4l/spi.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPI_H_ 2 | #define _SPI_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | #include "error.h" 7 | 8 | // Serial Peripheral Interface 9 | // This module allows the chip to communicate through an SPI interface, 10 | // either as a Master or a Slave. 11 | // SPI is faster than I2C, but uses more wires and can connect to less 12 | // peripherals at the same time. 13 | namespace SPI { 14 | 15 | // Peripheral memory space base addresses 16 | const uint32_t SPI_BASE = 0x40008000; 17 | 18 | // Register offsets 19 | const uint32_t OFFSET_CR = 0x00; // Control Register 20 | const uint32_t OFFSET_MR = 0x04; // Mode Register 21 | const uint32_t OFFSET_RDR = 0x08; // Receive Data Register 22 | const uint32_t OFFSET_TDR = 0x0C; // Transmit Data Register 23 | const uint32_t OFFSET_SR = 0x10; // Status Register 24 | const uint32_t OFFSET_IER = 0x14; // Interrupt Enable Register 25 | const uint32_t OFFSET_IDR = 0x18; // Interrupt Disable Register 26 | const uint32_t OFFSET_IMR = 0x1C; // Interrupt Mask Register 27 | const uint32_t OFFSET_CSR0 = 0x30; // Chip Select Register 0 28 | const uint32_t OFFSET_CSR1 = 0x34; // Chip Select Register 1 29 | const uint32_t OFFSET_CSR2 = 0x38; // Chip Select Register 2 30 | const uint32_t OFFSET_CSR3 = 0x3C; // Chip Select Register 3 31 | const uint32_t OFFSET_WPCR = 0xE4; // Write Protection Control Register 32 | const uint32_t OFFSET_WPSR = 0xE8; // Write Protection Status Register 33 | 34 | // Subregisters 35 | const uint8_t CR_SPIEN = 0; 36 | const uint8_t CR_SPIDIS = 1; 37 | const uint8_t CR_SWRST = 7; 38 | const uint8_t CR_FLUSHFIFO = 8; 39 | const uint8_t CR_LASTXFER = 24; 40 | const uint8_t MR_MSTR = 0; 41 | const uint8_t MR_PS = 1; 42 | const uint8_t MR_PCSDEC = 2; 43 | const uint8_t MR_MODFDIS = 4; 44 | const uint8_t MR_RXFIFOEN = 6; 45 | const uint8_t MR_LLB = 7; 46 | const uint8_t MR_PCS = 16; 47 | const uint8_t MR_DLYBCS = 24; 48 | const uint8_t TDR_TD = 0; 49 | const uint8_t TDR_PCS = 16; 50 | const uint8_t TDR_LASTXFER = 24; 51 | const uint8_t SR_RDRF = 0; 52 | const uint8_t SR_TDRE = 1; 53 | const uint8_t SR_MODF = 2; 54 | const uint8_t SR_OVRES = 3; 55 | const uint8_t SR_NSSR = 8; 56 | const uint8_t SR_TXEMPTY = 9; 57 | const uint8_t SR_UNDES = 10; 58 | const uint8_t SR_SPIENS = 16; 59 | const uint8_t CSR_CPOL = 0; 60 | const uint8_t CSR_NCPHA = 1; 61 | const uint8_t CSR_CSNAAT = 2; 62 | const uint8_t CSR_CSAAT = 3; 63 | const uint8_t CSR_BITS = 4; 64 | const uint8_t CSR_SCBR = 8; 65 | const uint8_t CSR_DLYBS = 16; 66 | const uint8_t CSR_DLYBCT = 24; 67 | const uint8_t WPCR_SPIWPEN = 0; 68 | 69 | // Constants 70 | const uint32_t WPCR_KEY = 0x535049 << 8; 71 | 72 | const int N_PERIPHERALS_MAX = 4; 73 | 74 | // Error codes 75 | const Error::Code ERR_INVALID_PERIPHERAL = 0x0001; 76 | const Error::Code ERR_PERIPHERAL_ALREADY_ENABLED = 0x0002; 77 | const Error::Code ERR_NOT_MASTER_MODE = 0x0003; 78 | const Error::Code ERR_NOT_SLAVE_MODE = 0x0004; 79 | 80 | // Static values 81 | enum class Mode { 82 | MODE0 = 0, // CPOL=0, CPHA=0 83 | MODE1 = 1, // CPOL=0, CPHA=1 84 | MODE2 = 2, // CPOL=1, CPHA=0 85 | MODE3 = 3 // CPOL=1, CPHA=1 86 | }; 87 | 88 | using Peripheral = uint8_t; 89 | 90 | enum class PinFunction { 91 | MOSI, 92 | MISO, 93 | SCK, 94 | CS0, 95 | CS1, 96 | CS2, 97 | CS3 98 | }; 99 | 100 | // Master-mode functions 101 | void enableMaster(); 102 | bool addPeripheral(Peripheral peripheral, Mode mode=Mode::MODE0); 103 | uint8_t transfer(Peripheral peripheral, uint8_t tx=0, bool next=false); 104 | void transfer(Peripheral peripheral, uint8_t* txBuffer, int txBufferSize, uint8_t* rxBuffer=nullptr, int rxBufferSize=-1, bool partial=false); 105 | 106 | // Slave-mode functions 107 | void enableSlave(Mode mode=Mode::MODE0); 108 | void slaveTransfer(uint8_t* txBuffer=nullptr, int txBufferSize=-1); 109 | bool isSlaveTransferFinished(); 110 | int slaveGetReceivedData(uint8_t* rxBuffer, int rxBufferSize); 111 | void enableSlaveTransferFinishedInterrupt(void (*handler)(int nReceivedBytes)); 112 | void disableSlaveTransferFinishedInterrupt(); 113 | 114 | // Common functions 115 | void disable(); 116 | void setPin(PinFunction function, GPIO::Pin pin); 117 | 118 | } 119 | 120 | 121 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/gloc.cpp: -------------------------------------------------------------------------------- 1 | #include "gloc.h" 2 | #include "pm.h" 3 | 4 | namespace GLOC { 5 | 6 | // Package-dependant, defined in pins_sam4l_XX.cpp 7 | extern struct GPIO::Pin PINS_IN[][4]; 8 | extern struct GPIO::Pin PINS_OUT[]; 9 | 10 | bool _filterEnabled[2] = {false, false}; 11 | 12 | 13 | void enable(LUT lut, bool in0, bool in1, bool in2, bool in3) { 14 | // Enable the clock 15 | PM::enablePeripheralClock(PM::CLK_GLOC); 16 | 17 | // Configure inputs 18 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_CR0)) 19 | = 0 << CR0_FILTEN // FILTEN : disable glitch filter 20 | | in0 << CR0_AEN // AEN : enable inputs 21 | | in1 << (CR0_AEN + 1) 22 | | in2 << (CR0_AEN + 2) 23 | | in3 << (CR0_AEN + 3); 24 | 25 | // Set pins in peripheral mode 26 | if (in0) { 27 | GPIO::enablePeripheral(PINS_IN[static_cast(lut)][0]); 28 | } 29 | if (in1) { 30 | GPIO::enablePeripheral(PINS_IN[static_cast(lut)][1]); 31 | } 32 | if (in2) { 33 | GPIO::enablePeripheral(PINS_IN[static_cast(lut)][2]); 34 | } 35 | if (in3) { 36 | GPIO::enablePeripheral(PINS_IN[static_cast(lut)][3]); 37 | } 38 | GPIO::enablePeripheral(PINS_OUT[static_cast(lut)]); 39 | } 40 | 41 | void disable(LUT lut) { 42 | // Free pins 43 | GPIO::disablePeripheral(PINS_IN[static_cast(lut)][0]); 44 | GPIO::disablePeripheral(PINS_IN[static_cast(lut)][1]); 45 | GPIO::disablePeripheral(PINS_IN[static_cast(lut)][2]); 46 | GPIO::disablePeripheral(PINS_IN[static_cast(lut)][3]); 47 | GPIO::disablePeripheral(PINS_OUT[static_cast(lut)]); 48 | } 49 | 50 | void set(LUT lut, bool output, bool in0, bool in1, bool in2, bool in3) { 51 | // Compute the offset corresponding to these inputs in the LUT 52 | int offset = in0 | (in1 << 1) | (in2 << 2) | (in3 << 3); 53 | 54 | // Update the truth table 55 | if (output) { 56 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_TRUTH0)) 57 | |= 1 << offset; 58 | } else { 59 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_TRUTH0)) 60 | &= ~(uint32_t)(1 << offset); 61 | } 62 | } 63 | 64 | void setLUT(LUT lut, uint16_t truth) { 65 | // Set the truth table 66 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_TRUTH0)) 67 | = truth << TRUTH0_TRUTH; 68 | } 69 | 70 | void enableFilter(LUT lut, SCIF::GCLKSource clock, uint16_t divider) { 71 | _filterEnabled[static_cast(lut)] = true; 72 | 73 | // Enable the generic clock on which the filter is based 74 | SCIF::enableGenericClock(SCIF::GCLKChannel::GCLK5_GLOC_TC0, clock, false, divider); 75 | 76 | // Enable the filter for this LUT 77 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_CR0)) 78 | |= 1 << CR0_FILTEN; 79 | } 80 | 81 | void disableFilter(LUT lut) { 82 | _filterEnabled[static_cast(lut)] = false; 83 | 84 | // Disable the generic clock on which the filter is based if it is not used anymore 85 | if (!_filterEnabled[0] && !_filterEnabled[1]) { 86 | SCIF::disableGenericClock(SCIF::GCLKChannel::GCLK5_GLOC_TC0); 87 | } 88 | 89 | // Disable the filter for this LUT 90 | (*(volatile uint32_t*)(GLOC_BASE + static_cast(lut) * GLOC_REG_SIZE + OFFSET_CR0)) 91 | &= ~(uint32_t)(1 << CR0_FILTEN); 92 | } 93 | 94 | void setPin(LUT lut, PinFunction function, GPIO::Pin pin) { 95 | switch (function) { 96 | case PinFunction::IN0: 97 | PINS_IN[static_cast(lut)][0] = pin; 98 | break; 99 | 100 | case PinFunction::IN1: 101 | PINS_IN[static_cast(lut)][1] = pin; 102 | break; 103 | 104 | case PinFunction::IN2: 105 | PINS_IN[static_cast(lut)][2] = pin; 106 | break; 107 | 108 | case PinFunction::IN3: 109 | PINS_IN[static_cast(lut)][3] = pin; 110 | break; 111 | 112 | case PinFunction::OUT: 113 | PINS_OUT[static_cast(lut)] = pin; 114 | break; 115 | } 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /libtungsten/ld_scripts/common.ld: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * 4 | * \brief Flash Linker script for SAM. 5 | * 6 | * Copyright (c) 2012-2013 Atmel Corporation. All rights reserved. 7 | * 8 | * \asf_license_start 9 | * 10 | * \page License 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * 3. The name of Atmel may not be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * 4. This software may only be redistributed and used in connection with an 26 | * Atmel microcontroller product. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * \asf_license_stop 41 | * 42 | */ 43 | 44 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 45 | OUTPUT_ARCH(arm) 46 | SEARCH_DIR(.) 47 | 48 | /* The stack size used by the application. NOTE: you need to adjust according to your application. */ 49 | __stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x1000; 50 | __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) - 4; 51 | 52 | /* Section Definitions */ 53 | SECTIONS 54 | { 55 | .text : 56 | { 57 | . = ALIGN(4); 58 | SECTION_TEXT_START = .; 59 | KEEP(*(.vectors .vectors.*)) 60 | *(.text .text.* .gnu.linkonce.t.*) 61 | *(.glue_7t) *(.glue_7) 62 | *(.rodata .rodata* .gnu.linkonce.r.*) 63 | *(.ARM.extab* .gnu.linkonce.armextab.*) 64 | 65 | /* Support C constructors, and C destructors in both user code 66 | and the C library. This also provides support for C++ code. */ 67 | . = ALIGN(4); 68 | KEEP(*(.init)) 69 | . = ALIGN(4); 70 | __preinit_array_start = .; 71 | KEEP (*(.preinit_array)) 72 | __preinit_array_end = .; 73 | 74 | . = ALIGN(4); 75 | __init_array_start = .; 76 | KEEP (*(SORT(.init_array.*))) 77 | KEEP (*(.init_array)) 78 | __init_array_end = .; 79 | 80 | . = ALIGN(0x4); 81 | KEEP (*crtbegin.o(.ctors)) 82 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 83 | KEEP (*(SORT(.ctors.*))) 84 | KEEP (*crtend.o(.ctors)) 85 | 86 | . = ALIGN(4); 87 | KEEP(*(.fini)) 88 | 89 | . = ALIGN(4); 90 | __fini_array_start = .; 91 | KEEP (*(.fini_array)) 92 | KEEP (*(SORT(.fini_array.*))) 93 | __fini_array_end = .; 94 | 95 | KEEP (*crtbegin.o(.dtors)) 96 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 97 | KEEP (*(SORT(.dtors.*))) 98 | KEEP (*crtend.o(.dtors)) 99 | 100 | . = ALIGN(4); 101 | SECTION_TEXT_END = .; 102 | } > FLASH 103 | 104 | /* .ARM.exidx is sorted, so has to go in its own output section. */ 105 | PROVIDE_HIDDEN (__exidx_start = .); 106 | .ARM.exidx : 107 | { 108 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 109 | } > FLASH 110 | PROVIDE_HIDDEN (__exidx_end = .); 111 | 112 | . = ALIGN(4); 113 | SECTION_DATA_START = .; 114 | 115 | .relocate : AT (SECTION_DATA_START) 116 | { 117 | . = ALIGN(4); 118 | SECTION_RELOCATE_START = .; 119 | *(.ramfunc .ramfunc.*); 120 | *(.data .data.*); 121 | . = ALIGN(4); 122 | SECTION_RELOCATE_END = .; 123 | } > RAM 124 | 125 | /* .bss section which is used for uninitialized data */ 126 | .bss (NOLOAD) : 127 | { 128 | . = ALIGN(4); 129 | SECTION_BSS_START = . ; 130 | *(.bss .bss.*) 131 | *(COMMON) 132 | . = ALIGN(4); 133 | SECTION_BSS_END = . ; 134 | } > RAM 135 | 136 | /* stack section */ 137 | .stack (NOLOAD): 138 | { 139 | . = ALIGN(8); 140 | SECTION_STACK_START = .; 141 | . = . + __stack_size__; 142 | . = ALIGN(8); 143 | SECTION_STACK_END = .; 144 | } > RAM 145 | 146 | . = ALIGN(4); 147 | _end = . ; 148 | } 149 | -------------------------------------------------------------------------------- /libtungsten/sam4l/bscif.cpp: -------------------------------------------------------------------------------- 1 | #include "bscif.h" 2 | #include "bpm.h" 3 | 4 | namespace BSCIF { 5 | 6 | unsigned long _osc32kFrequency = 0; 7 | unsigned long _rc32kFrequency = 0; 8 | unsigned long _rc1mFrequency = 0; 9 | 10 | void enableOSC32K() { 11 | // Save the frequency for future use 12 | _osc32kFrequency = 32768; 13 | 14 | // Unlock the OSCCTRL32 register, which is locked by default as a safety mesure 15 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK)) 16 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 17 | | OFFSET_OSCCTRL32; // ADDR : unlock OSCCTRL32 18 | 19 | // Configure OSC32 20 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_OSCCTRL32)) 21 | = 1 << OSCCTRL32_EN32K // EN32K : enable 32kHz output 22 | | 1 << OSCCTRL32_EN1K // EN1K : enable 1kHz output 23 | | 3 << OSCCTRL32_MODE // MODE : crystal 24 | | 8 << OSCCTRL32_SELCURR // SELCURR : current driven into the crystal 25 | | 0 << OSCCTRL32_STARTUP; // STARTUP : oscillator startup time 26 | 27 | // Enable OSC32 28 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_OSCCTRL32)) 29 | |= 1 << OSCCTRL32_OSC32EN; // OSC32EN : enable crystal 30 | 31 | // Wait for OSC32K to be ready 32 | while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_OSC32RDY))); 33 | 34 | // Select OSC32K as the 32KHz clock source 35 | BPM::set32KHzClockSource(BPM::CLK32KSource::OSC32K); 36 | } 37 | 38 | unsigned long getOSC32KFrequency() { 39 | return _osc32kFrequency; 40 | } 41 | 42 | void enableRC32K() { 43 | // Save the frequency for future use 44 | _rc32kFrequency = 32768; 45 | 46 | // Unlock the RC32KCR register, which is locked by default as a safety mesure 47 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK)) 48 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 49 | | OFFSET_RC32KCR; // ADDR : unlock RC32KCR 50 | 51 | // Configure RC32K 52 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC32KCR)) 53 | = 1 << RC32KCR_TCEN // TCEN : enable temperature compensation 54 | | 1 << RC32KCR_EN32K // EN32K : enable 32kHz output 55 | | 1 << RC32KCR_EN1K // EN1K : enable 1kHz output 56 | | 1 << RC32KCR_MODE // MODE : closed loop mode 57 | | 0 << RC32KCR_REF; // REF : closed loop mode reference : OSC32K 58 | 59 | // Enable RC32K 60 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC32KCR)) 61 | |= 1 << RC32KCR_EN; // EN : enable generic clock source 62 | 63 | // Wait for RC32K to be ready 64 | while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & ((1 << PCLKSR_RC32KRDY) | (1 << PCLKSR_RC32KLOCK)))); 65 | 66 | // Select RC32K as the 32KHz clock source 67 | BPM::set32KHzClockSource(BPM::CLK32KSource::RC32K); 68 | } 69 | 70 | unsigned long getRC32KFrequency() { 71 | return _rc32kFrequency; 72 | } 73 | 74 | void enableRC1M() { 75 | // Save the frequency for future use 76 | _rc1mFrequency = 1000000; 77 | 78 | // Unlock the RC1MCR register, which is locked by default as a safety mesure 79 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK)) 80 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 81 | | OFFSET_RC1MCR; // ADDR : unlock RC1MCR 82 | 83 | // Configure RC1M 84 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC1MCR)) 85 | = 1 << RC1MCR_CLKOEN; // CLKOEN : enable oscillator 86 | 87 | // Wait for RC1M to be ready 88 | while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_RC1MRDY))); 89 | } 90 | 91 | unsigned long getRC1MFrequency() { 92 | return _rc1mFrequency; 93 | } 94 | 95 | // Store data in one of the four 32-bit backup registers 96 | // This data is kept even in BACKUP low-power mode, when all other 97 | // registers not in the Backup domain are lost 98 | void storeBackupData(int n, uint32_t data) { 99 | // Register offset 100 | if (n < 0 || n > 3) { 101 | return; 102 | } 103 | const uint32_t offset = OFFSET_BR + n * 4; 104 | 105 | // Unlock the BRn register, which is locked by default as a safety mesure 106 | (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK)) 107 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 108 | | offset; // ADDR : unlock BRn 109 | 110 | // Store data 111 | (*(volatile uint32_t*)(BSCIF_BASE + offset)) = data; 112 | } 113 | 114 | // Read data from one of the four 32-bit backup registers 115 | uint32_t readBackupData(int n) { 116 | // Register offset 117 | if (n < 0 || n > 3) { 118 | return 0; 119 | } 120 | const uint32_t offset = OFFSET_BR + n * 4; 121 | 122 | return (*(volatile uint32_t*)(BSCIF_BASE + offset)); 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/usart.h: -------------------------------------------------------------------------------- 1 | #ifndef _USART_H_ 2 | #define _USART_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | 7 | // Universal Synchronous Asynchronous Receiver Transmitter 8 | // This module allows the chip to communicate on an RS232 link 9 | // (also sometimes called Serial port) 10 | namespace USART { 11 | 12 | // Peripheral memory space base addresses 13 | const uint32_t USART_BASE = 0x40024000; 14 | const uint32_t USART_REG_SIZE = 0x4000; 15 | 16 | // Register offsets 17 | const uint32_t OFFSET_CR = 0x00; 18 | const uint32_t OFFSET_MR = 0x04; 19 | const uint32_t OFFSET_IER = 0x08; 20 | const uint32_t OFFSET_IDR = 0x0C; 21 | const uint32_t OFFSET_IMR = 0x10; 22 | const uint32_t OFFSET_CSR = 0x14; 23 | const uint32_t OFFSET_RHR = 0x18; 24 | const uint32_t OFFSET_THR = 0x1C; 25 | const uint32_t OFFSET_BRGR = 0x20; 26 | const uint32_t OFFSET_RTOR = 0x24; 27 | const uint32_t OFFSET_TTGR = 0x28; 28 | const uint32_t OFFSET_FIDI = 0x40; 29 | const uint32_t OFFSET_NER = 0x44; 30 | const uint32_t OFFSET_IFR = 0x4C; 31 | const uint32_t OFFSET_MAN = 0x50; 32 | const uint32_t OFFSET_LINMR = 0x54; 33 | const uint32_t OFFSET_LINIR = 0x58; 34 | const uint32_t OFFSET_LINBR = 0x5C; 35 | const uint32_t OFFSET_WPMR = 0xE4; 36 | const uint32_t OFFSET_WPSR = 0xE8; 37 | const uint32_t OFFSET_VERSION = 0xFC; 38 | 39 | // Subregisters 40 | const uint32_t CR_RSTRX = 2; 41 | const uint32_t CR_RSTTX = 3; 42 | const uint32_t CR_RXEN = 4; 43 | const uint32_t CR_RXDIS = 5; 44 | const uint32_t CR_TXEN = 6; 45 | const uint32_t CR_TXDIS = 7; 46 | const uint32_t CR_RSTSTA = 8; 47 | const uint32_t MR_MODE = 0; 48 | const uint32_t MR_CHRL = 6; 49 | const uint32_t MR_PAR = 9; 50 | const uint32_t MR_NBSTOP = 12; 51 | const uint32_t MR_MODE9 = 17; 52 | const uint32_t BRGR_CD = 0; 53 | const uint32_t BRGR_FP = 16; 54 | const uint32_t CSR_RXRDY = 0; 55 | const uint32_t CSR_TXRDY = 1; 56 | const uint32_t CSR_RXBRK = 2; 57 | const uint32_t CSR_OVRE = 5; 58 | const uint32_t CSR_PARE = 7; 59 | const uint32_t CSR_TXEMPTY = 9; 60 | const uint32_t IER_RXRDY = 0; 61 | 62 | // Constants 63 | const uint32_t WPMR_KEY = 0x555341 << 8; 64 | const uint32_t WPMR_ENABLE = 1; 65 | const uint32_t WPMR_DISABLE = 0; 66 | const uint32_t MODE_NORMAL = 0b0000; 67 | const uint32_t MODE_HARDWARE_HANDSHAKE = 0b0010; 68 | 69 | const int N_PORTS = 4; 70 | enum class Port { 71 | USART0, 72 | USART1, 73 | USART2, 74 | USART3 75 | }; 76 | 77 | const uint8_t BIN = 2; 78 | const uint8_t DEC = 10; 79 | const uint8_t HEX = 16; 80 | 81 | // Port configuration : character length (default 8) 82 | // Value refers to MR.CHRL and MR.MODE9 83 | enum class CharLength { 84 | CHAR5 = 0b000, 85 | CHAR6 = 0b001, 86 | CHAR7 = 0b010, 87 | CHAR8 = 0b011, 88 | CHAR9 = 0b100 89 | }; 90 | 91 | // Port configuration : parity type (default NONE) 92 | // Value refers to MR.PAR 93 | enum class Parity { 94 | EVEN = 0b000, 95 | ODD = 0b001, 96 | SPACE = 0b010, // Parity forced to 0 97 | MARK = 0b011, // Parity forced to 1 98 | NONE = 0b100, 99 | }; 100 | 101 | // Port configuration : length of stop bit (default 1) 102 | // Value refers to MR.NBSTOP 103 | enum class StopBit { 104 | STOP1 = 0b00, 105 | STOP15 = 0b01, // length 1.5 bit 106 | STOP2 = 0b10 107 | }; 108 | 109 | const int N_INTERRUPTS = 4; 110 | enum class Interrupt { 111 | BYTE_RECEIVED, 112 | TRANSMIT_READY, 113 | OVERFLOW, 114 | PARITY_ERROR 115 | }; 116 | 117 | enum class PinFunction { 118 | RX, 119 | TX, 120 | RTS, 121 | CTS 122 | }; 123 | 124 | const int BUFFER_SIZE = 2048; 125 | 126 | 127 | // Error codes 128 | const Error::Code ERR_BAUDRATE_OUT_OF_RANGE = 0x0001; 129 | 130 | 131 | // Module API 132 | void enable(Port port, unsigned long baudrate, bool hardwareFlowControl=false, CharLength charLength=CharLength::CHAR8, Parity parity=Parity::NONE, StopBit stopBit=StopBit::STOP1); 133 | void disable(Port port); 134 | void enableInterrupt(Port port, void (*handler)(), Interrupt interrupt); 135 | int available(Port port); 136 | bool contains(Port port, char byte); 137 | char peek(Port port); 138 | bool peek(Port port, const char* test, int size); 139 | char read(Port port); 140 | int read(Port port, char* buffer, int size, bool readUntil=false, char end=0x00); 141 | int readUntil(Port port, char* buffer, int size, char end); 142 | unsigned long readInt(Port port, int nBytes, bool wait=true); 143 | int write(Port port, const char* buffer, int size=-1, bool async=false); 144 | int write(Port port, char byte, bool async=false); 145 | int write(Port port, int number, uint8_t base, bool async=false); 146 | int write(Port port, bool boolean, bool async=false); 147 | int writeLine(Port port, const char* buffer, int size=-1, bool async=false); 148 | int writeLine(Port port, char byte, bool async=false); 149 | int writeLine(Port port, int number, uint8_t base, bool async=false); 150 | int writeLine(Port port, bool boolean, bool async=false); 151 | bool isWriteFinished(Port port); 152 | void waitWriteFinished(Port port); 153 | void waitReadFinished(Port port, unsigned long timeout=100); 154 | void flush(Port port); 155 | void setPin(Port port, PinFunction function, GPIO::Pin pin); 156 | 157 | } 158 | 159 | 160 | #endif -------------------------------------------------------------------------------- /sync_usb.cpp: -------------------------------------------------------------------------------- 1 | #include "sync_usb.h" 2 | #include "sync.h" 3 | #include "context.h" 4 | #include 5 | 6 | namespace SyncUSB { 7 | 8 | enum class Request { 9 | FOCUS, 10 | TRIGGER, 11 | }; 12 | 13 | volatile bool _connected = false; 14 | bool _commandAvailable = false; 15 | Request _command = Request::FOCUS; 16 | uint8_t _payload[Sync::MAX_PAYLOAD_SIZE]; 17 | volatile int _payloadSize = 0; 18 | uint8_t _sendingBuffer[Sync::MAX_PAYLOAD_SIZE + 1]; 19 | volatile int _sendingBufferSize = 0; 20 | 21 | 22 | void init() { 23 | USB::initDevice(USB_VENDOR_ID, USB_PRODUCT_ID); 24 | USB::setStringDescriptor(USB::StringDescriptors::MANUFACTURER, STR_MANUFACTURER, sizeof(STR_MANUFACTURER) - 1); 25 | USB::setStringDescriptor(USB::StringDescriptors::PRODUCT, STR_PRODUCT, sizeof(STR_PRODUCT) - 1); 26 | USB::setStringDescriptor(USB::StringDescriptors::SERIALNUMBER, STR_SERIALNUMBER, sizeof(STR_SERIALNUMBER) - 1); 27 | USB::setConnectedHandler(usbConnectedHandler); 28 | USB::setDisconnectedHandler(usbDisconnectedHandler); 29 | USB::setControlHandler(usbControlHandler); 30 | } 31 | 32 | bool commandAvailable() { 33 | return _commandAvailable; 34 | } 35 | 36 | uint8_t getCommand() { 37 | _commandAvailable = false; 38 | return static_cast(_command); 39 | } 40 | 41 | int getPayload(uint8_t* buffer) { 42 | _commandAvailable = false; 43 | memcpy(buffer, _payload, _payloadSize); 44 | return _payloadSize; 45 | } 46 | 47 | void send(uint8_t command, uint8_t* payload, int payloadSize) { 48 | for (int i = 0; i < 500; i++) { 49 | if (_sendingBufferSize == 0) { 50 | break; 51 | } 52 | if (!_connected) { 53 | return; 54 | } 55 | Core::sleep(1); 56 | } 57 | if (payloadSize > Sync::MAX_PAYLOAD_SIZE) { 58 | payloadSize = Sync::MAX_PAYLOAD_SIZE; 59 | } 60 | _sendingBuffer[0] = command; 61 | memcpy(_sendingBuffer + 1, payload, payloadSize); 62 | _sendingBufferSize = payloadSize + 1; 63 | } 64 | 65 | bool isConnected() { 66 | return _connected; 67 | } 68 | 69 | void resetState() { 70 | _sendingBufferSize = 0; 71 | _commandAvailable = false; 72 | } 73 | 74 | void usbConnectedHandler() { 75 | resetState(); 76 | _connected = true; 77 | } 78 | 79 | void usbDisconnectedHandler() { 80 | resetState(); 81 | _connected = false; 82 | } 83 | 84 | // Handler called when a CONTROL packet is sent over USB 85 | int usbControlHandler(USB::SetupPacket &lastSetupPacket, uint8_t* data, int size) { 86 | // Get command 87 | _command = static_cast(lastSetupPacket.bRequest); 88 | 89 | if (lastSetupPacket.direction == USB::EPDir::OUT) { 90 | // Get payload 91 | _payloadSize = size; 92 | if (_payloadSize > Sync::MAX_PAYLOAD_SIZE) { 93 | _payloadSize = Sync::MAX_PAYLOAD_SIZE; 94 | } 95 | memcpy(_payload, data, _payloadSize); 96 | 97 | _commandAvailable = true; 98 | lastSetupPacket.handled = true; 99 | } else { // IN 100 | if (lastSetupPacket.bRequest == Sync::CMD_GET_GUI_STATE) { 101 | lastSetupPacket.handled = true; 102 | uint8_t buffer[] = { 103 | static_cast(Context::_submenuFocusHold), 104 | static_cast(Context::_submenuTriggerHold), 105 | static_cast(Context::_triggerSync), 106 | static_cast(Context::_delayMs / 100 >> 16), 107 | static_cast(Context::_delayMs / 100 >> 8), 108 | static_cast(Context::_delayMs / 100), 109 | static_cast(Context::_delaySync), 110 | static_cast(Context::_intervalNShots), 111 | static_cast(Context::_intervalDelayMs / 100 >> 16), 112 | static_cast(Context::_intervalDelayMs / 100 >> 8), 113 | static_cast(Context::_intervalDelayMs / 100), 114 | static_cast(Context::_intervalSync), 115 | static_cast(Context::_inputMode), 116 | static_cast(Context::_inputSync), 117 | static_cast(Context::_syncChannel), 118 | static_cast(Context::_timingsFocusDurationMs / 100 >> 16), 119 | static_cast(Context::_timingsFocusDurationMs / 100 >> 8), 120 | static_cast(Context::_timingsFocusDurationMs / 100), 121 | static_cast(Context::_timingsTriggerDurationMs / 100 >> 16), 122 | static_cast(Context::_timingsTriggerDurationMs / 100 >> 8), 123 | static_cast(Context::_timingsTriggerDurationMs / 100), 124 | static_cast(Context::_timingsSync) 125 | }; 126 | int payloadSize = sizeof(buffer); 127 | if (size < payloadSize) { 128 | payloadSize = size; 129 | } 130 | memcpy(data, buffer, payloadSize); 131 | return payloadSize; 132 | 133 | } else if (lastSetupPacket.bRequest == Sync::CMD_GET_GUI_UPDATE) { 134 | lastSetupPacket.handled = true; 135 | int size = _sendingBufferSize; 136 | memcpy(data, _sendingBuffer, size); 137 | _sendingBufferSize = 0; 138 | return size; 139 | } 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/ast.cpp: -------------------------------------------------------------------------------- 1 | #include "ast.h" 2 | #include "core.h" 3 | 4 | namespace AST { 5 | 6 | // Represents the highest 32 bits of the 64-bit current time 7 | // The lowest 32 bits are taken from the Current Value Register (CV) 8 | // See time() 9 | Time _currentTimeHighBytes = 0; 10 | 11 | // User handler for the Alarm interrupt 12 | void (*_alarmHandler)(); 13 | extern uint8_t INTERRUPT_PRIORITY; 14 | 15 | 16 | // Internal functions 17 | void overflowHandler(); 18 | void alarmHandlerWrapper(); 19 | inline void waitWhileBusy() { 20 | while ((*(volatile uint32_t*)(BASE + OFFSET_SR)) & (1 << SR_BUSY)); 21 | }; 22 | 23 | 24 | // Note : the CR, CV, SCR, WER, EVE, EVD, ARn, PIRn, and DTR registers 25 | // cannot be read or written when SR.BUSY is set, because the peripheral 26 | // is synchronizing them between the two clock domains 27 | 28 | 29 | // Initialize and enable the AST counter with the 32768Hz clock divided by 2 as input 30 | void init() { 31 | // See datasheet §19.5.1 Initialization 32 | 33 | // Select the clock 34 | (*(volatile uint32_t*)(BASE + OFFSET_CLOCK)) 35 | = 1 << CLOCK_CSSEL; // 32kHz clock (OSC32 or RC32) 36 | while ((*(volatile uint32_t*)(BASE + OFFSET_SR)) & (1 << SR_CLKBUSY)); 37 | 38 | // Enable the clock 39 | (*(volatile uint32_t*)(BASE + OFFSET_CLOCK)) 40 | |= 1 << CLOCK_CEN; 41 | while ((*(volatile uint32_t*)(BASE + OFFSET_SR)) & (1 << SR_CLKBUSY)); 42 | 43 | // IER (Interrupt Enable Register) : enable the Overflow interrupt 44 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) = 1 << SR_OVF; 45 | 46 | // Set the handler and enable the module interrupt at the Core level 47 | Core::setInterruptHandler(Core::Interrupt::AST_OVF, overflowHandler); 48 | Core::enableInterrupt(Core::Interrupt::AST_OVF, INTERRUPT_PRIORITY); 49 | 50 | // Enable wake-up for the OVF interrupt 51 | waitWhileBusy(); 52 | (*(volatile uint32_t*)(BASE + OFFSET_WER)) 53 | = 1 << SR_OVF; 54 | 55 | // Reset the counter value 56 | waitWhileBusy(); 57 | (*(volatile uint32_t*)(BASE + OFFSET_CV)) = 0; 58 | 59 | // Reset the prescaler value 60 | (*(volatile uint32_t*)(BASE + OFFSET_CR)) 61 | |= 1 << CR_PCLR; 62 | 63 | // Disable the digital tuner 64 | waitWhileBusy(); 65 | (*(volatile uint32_t*)(BASE + OFFSET_DTR)) = 0; 66 | 67 | // CR.PSEL is kept to 0, which means the prescaler will divide 68 | // the input clock frequency by 2 69 | 70 | // Enable the counter 71 | waitWhileBusy(); 72 | (*(volatile uint32_t*)(BASE + OFFSET_CR)) 73 | = 1 << CR_EN; 74 | } 75 | 76 | void enableAlarm(Time time, bool relative, void (*handler)(), bool wake) { 77 | // Critical section 78 | Core::disableInterrupts(); 79 | 80 | // Set the user handler 81 | _alarmHandler = handler; 82 | 83 | // Enable wake-up for the ALARM interrupt 84 | if (wake) { 85 | waitWhileBusy(); 86 | (*(volatile uint32_t*)(BASE + OFFSET_WER)) 87 | = 1 << SR_ALARM0; 88 | } 89 | 90 | // IDR (Interrupt Disable Register) : disable the Alarm interrupt 91 | (*(volatile uint32_t*)(BASE + OFFSET_IDR)) = 1 << SR_ALARM0; 92 | 93 | // SCR (Status Clear Register) : clear the interrupt 94 | waitWhileBusy(); 95 | (*(volatile uint32_t*)(BASE + OFFSET_SCR)) = 1 << SR_ALARM0; 96 | 97 | // Convert the time from ms to clock cycles 98 | // Remember that the 32768Hz input clock is prescaled by a factor of 2 99 | time = (time * (32768/2)) / 1000; 100 | 101 | // Substract 2 clock cycles from the time to account for the function overhead 102 | if (time > 2) { 103 | time -= 2; 104 | } else { 105 | time = 0; 106 | } 107 | 108 | // Set the alarm time 109 | // The 32-bit truncate is not a problem as long as the alarm is not more than 110 | // ~ 36 hours in the future : (2^32) cycles / 36768 = 131072s ~= 36h 111 | waitWhileBusy(); 112 | if (relative) { 113 | if (time < 2) { 114 | time = 2; 115 | } 116 | time += *(volatile uint32_t*)(BASE + OFFSET_CV); 117 | } 118 | (*(volatile uint32_t*)(BASE + OFFSET_AR0)) = (uint32_t)time; 119 | 120 | // IER (Interrupt Enable Register) : enable the Alarm interrupt 121 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) = 1 << SR_ALARM0; 122 | 123 | // Enable the module interrupt at the Core level 124 | Core::setInterruptHandler(Core::Interrupt::AST_ALARM, alarmHandlerWrapper); 125 | Core::enableInterrupt(Core::Interrupt::AST_ALARM, INTERRUPT_PRIORITY); 126 | 127 | // End of critical section 128 | Core::enableInterrupts(); 129 | } 130 | 131 | void disableAlarm() { 132 | // IDR (Interrupt Disable Register) : disable the Alarm interrupt 133 | (*(volatile uint32_t*)(BASE + OFFSET_IDR)) = 1 << SR_ALARM0; 134 | } 135 | 136 | void overflowHandler() { 137 | // Increment the high bytes of the 64-bit counter 138 | _currentTimeHighBytes += (uint64_t)1 << 32; 139 | 140 | // SCR (Status Clear Register) : clear the interrupt 141 | waitWhileBusy(); 142 | (*(volatile uint32_t*)(BASE + OFFSET_SCR)) = 1 << SR_OVF; 143 | } 144 | 145 | void alarmHandlerWrapper() { 146 | // Call the user handler if defined 147 | if (_alarmHandler != nullptr) { 148 | _alarmHandler(); 149 | } 150 | 151 | // Disable the alarm so it is not triggered again after 152 | // the next counter overflow 153 | disableAlarm(); 154 | 155 | // SCR (Status Clear Register) : clear the interrupt 156 | waitWhileBusy(); 157 | (*(volatile uint32_t*)(BASE + OFFSET_SCR)) = 1 << SR_ALARM0; 158 | } 159 | 160 | bool alarmPassed() { 161 | return *(volatile uint32_t*)(BASE + OFFSET_CV) >= *(volatile uint32_t*)(BASE + OFFSET_AR0); 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /libtungsten/usbcom/USBCom.cpp: -------------------------------------------------------------------------------- 1 | #include "USBCom.h" 2 | 3 | #include 4 | 5 | const std::string LIBUSB_ERROR_STRINGS[] = { 6 | "SUCCESS", 7 | "ERROR_IO", 8 | "ERROR_INVALID_PARAM", 9 | "ERROR_ACCESS", 10 | "ERROR_NO_DEVICE", 11 | "ERROR_NOT_FOUND", 12 | "ERROR_BUSY", 13 | "ERROR_TIMEOUT", 14 | "ERROR_OVERFLOW", 15 | "ERROR_PIPE", 16 | "ERROR_INTERRUPTED", 17 | "ERROR_NO_MEM", 18 | "ERROR_NOT_SUPPORTED" 19 | }; 20 | 21 | const uint8_t REQ_BOOTLOADER = 0x00; 22 | const uint8_t REQ_CONNECT = 0x01; 23 | const uint8_t REQ_DISCONNECT = 0x02; 24 | 25 | 26 | int USBCom::init() { 27 | int r = 0; 28 | 29 | // Init libusb 30 | r = libusb_init(NULL); 31 | if (r < 0) { 32 | printLibUSBError("Unable to initialize libusb", r); 33 | return r; 34 | } 35 | 36 | // Find a matching usb device 37 | r = findDevice(DEFAULT_USB_VENDOR_ID, DEFAULT_USB_PRODUCT_ID); 38 | if (r < 0) { 39 | return r; 40 | } 41 | 42 | // Set the device's default configuration 43 | r = libusb_set_configuration(_handle, 0); 44 | if (r < 0) { 45 | printLibUSBError("libusb_set_configuration failed", r); 46 | libusb_close(_handle); 47 | return r; 48 | } 49 | 50 | // Remove any active driver to take control of the interface 51 | if (libusb_kernel_driver_active(_handle, DEFAULT_INTERFACE)) { 52 | r = libusb_detach_kernel_driver(_handle, DEFAULT_INTERFACE); 53 | if (r < 0) { 54 | printLibUSBError("Unable to detach kernel driver", r); 55 | libusb_close(_handle); 56 | return r; 57 | } 58 | } 59 | 60 | // Claim the interface 61 | r = libusb_claim_interface(_handle, DEFAULT_INTERFACE); 62 | if (r < 0) { 63 | printLibUSBError("Unable to claim device's interface", r); 64 | libusb_close(_handle); 65 | return r; 66 | } 67 | 68 | sendRequestInternal(REQ_CONNECT); 69 | 70 | return LIBUSB_SUCCESS; 71 | } 72 | 73 | void USBCom::close() { 74 | if (_handle == nullptr) { 75 | return; 76 | } 77 | sendRequestInternal(REQ_DISCONNECT); 78 | libusb_close(_handle); 79 | _handle = nullptr; 80 | } 81 | 82 | int USBCom::read(uint8_t* buffer, int maxLength, int timeout) { 83 | int transferredLength = 0; 84 | int r = libusb_bulk_transfer(_handle, LIBUSB_ENDPOINT_IN | 1, buffer, maxLength, &transferredLength, timeout); 85 | if (r < 0) { 86 | printLibUSBError("Error during read", r); 87 | exit(r); 88 | } 89 | return transferredLength; 90 | } 91 | 92 | int USBCom::write(const uint8_t* buffer, int length, int timeout) { 93 | int transferredLength = 0; 94 | int r = libusb_bulk_transfer(_handle, 2, (uint8_t*)buffer, length, &transferredLength, timeout); 95 | if (r < 0) { 96 | printLibUSBError("Error during read", r); 97 | exit(r); 98 | } 99 | return transferredLength; 100 | } 101 | 102 | int USBCom::sendRequest(uint8_t request, uint16_t value, uint16_t index, Direction direction, uint8_t* buffer, uint16_t length, int timeout) { 103 | return USBCom::sendRequestInternal(request | 0x80, value, index, direction, buffer, length, timeout); 104 | } 105 | 106 | int USBCom::sendRequestInternal(uint8_t request, uint16_t value, uint16_t index, Direction direction, uint8_t* buffer, uint16_t length, int timeout) { 107 | uint8_t bmRequestType 108 | = static_cast(direction) << 7 // Direction 109 | | 2 << 5 // Type : vendor 110 | | 0; // Recipent : device 111 | int r = libusb_control_transfer(_handle, bmRequestType, request, value, index, buffer, length, timeout); 112 | if (r < 0) { 113 | printLibUSBError("Error during request transfer", r); 114 | exit(0); 115 | } 116 | return r; 117 | } 118 | 119 | 120 | 121 | 122 | int USBCom::findDevice(uint16_t vid, uint16_t pid) { 123 | int r = 0; 124 | int returnCode = 0; 125 | 126 | // Get the list of devices 127 | libusb_device** list; 128 | libusb_device* board = nullptr; 129 | ssize_t cnt = libusb_get_device_list(NULL, &list); 130 | if (cnt < 0) { 131 | printLibUSBError("Unable to find the list of usb devices", r); 132 | return r; 133 | } 134 | 135 | // Look for a device with the matching vendor and product ids 136 | for (ssize_t i = 0; i < cnt; i++) { 137 | libusb_device *device = list[i]; 138 | struct libusb_device_descriptor desc; 139 | r = libusb_get_device_descriptor(device, &desc); 140 | if (r < 0) { 141 | std::cerr << "Warning : unable to get descriptor for device (bus " 142 | << libusb_get_bus_number(device) << ", device " << libusb_get_device_address(device) << ")" << std::endl; 143 | continue; 144 | } 145 | if (desc.idVendor == vid && desc.idProduct == pid) { 146 | // Found matching device 147 | if (board == nullptr) { 148 | board = device; 149 | } else { 150 | std::cout << "Warning : more than one matching device found, are there multiple boards plugged in? The first match will be used." << std::endl; 151 | break; 152 | } 153 | } 154 | } 155 | 156 | if (board != nullptr) { 157 | // Open the device 158 | r = libusb_open(board, &_handle); 159 | if (r < 0) { 160 | //std::cerr << "Unable to open device 0x" << std::hex << vid << ":0x" << pid << std::dec << " : error " << r << std::endl; 161 | printLibUSBError("Unable to open device", r); 162 | if (r == LIBUSB_ERROR_IO) { 163 | std::cerr << "Please try again" << std::endl; 164 | } 165 | returnCode = r; 166 | } 167 | } else { 168 | returnCode = LIBUSB_ERROR_NO_DEVICE; 169 | } 170 | 171 | // Free the device list and return true if a device was found and opened correctly 172 | libusb_free_device_list(list, 1); 173 | return returnCode; 174 | } 175 | 176 | void USBCom::printLibUSBError(std::string message, int r) { 177 | std::cerr << message << " : "; 178 | if (-r <= 12) { 179 | std::cerr << LIBUSB_ERROR_STRINGS[-r] << std::endl; 180 | } else { 181 | std::cerr << "error " << r << std::endl; 182 | } 183 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/flash.cpp: -------------------------------------------------------------------------------- 1 | #include "flash.h" 2 | 3 | namespace Flash { 4 | 5 | bool isReady() { 6 | return (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FSR)) & (1 << FSR_FRDY); 7 | } 8 | 9 | uint32_t read(uint32_t address) { 10 | // Wait for the flash to be ready 11 | while (!isReady()); 12 | 13 | // Return the word at the specified address 14 | return (*(volatile uint32_t*)(FLASH_ARRAY_BASE + address)); 15 | } 16 | 17 | void readPage(int page, uint32_t data[]) { 18 | // Wait for the flash to be ready 19 | while (!isReady()); 20 | 21 | // Copy the buffer to the page buffer 22 | for (int i = 0; i < FLASH_PAGE_SIZE_WORDS; i++) { 23 | data[i] = (*(volatile uint32_t*)(FLASH_ARRAY_BASE + page * FLASH_PAGE_SIZE_BYTES + i * 4)); 24 | } 25 | } 26 | 27 | void erasePage(int page) { 28 | // Wait for the flash to be ready 29 | while (!isReady()); 30 | 31 | // FCMD (Flash Command Register) : issue an Erase Page command 32 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 33 | = FCMD_CMD_EP << FCMD_CMD // CMD : command code to issue (EP = Erase Page) 34 | | page << FCMD_PAGEN // PAGEN : page number 35 | | FCMD_KEY; // KEY : write protection key 36 | } 37 | 38 | void clearPageBuffer() { 39 | // Wait for the flash to be ready 40 | while (!isReady()); 41 | 42 | // FCMD (Flash Command Register) : issue a Clear Page Buffer command 43 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 44 | = FCMD_CMD_CPB << FCMD_CMD // CMD : command code to issue (CPB = Clear Page Buffer) 45 | | FCMD_KEY; // KEY : write protection key 46 | } 47 | 48 | void writePage(int page, const uint32_t data[]) { 49 | // The flash technology only allows 1-to-0 transitions, so the 50 | // page and the buffer must first be cleared (set to 1) 51 | erasePage(page); 52 | clearPageBuffer(); 53 | 54 | // Wait for the flash to be ready 55 | while (!isReady()); 56 | 57 | // Copy the buffer to the page buffer 58 | for (int i = 0; i < FLASH_PAGE_SIZE_WORDS; i++) { 59 | (*(volatile uint32_t*)(FLASH_ARRAY_BASE + page * FLASH_PAGE_SIZE_BYTES + i * 4)) = data[i]; 60 | } 61 | 62 | // FCMD (Flash Command Register) : issue a Write Page command 63 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 64 | = FCMD_CMD_WP << FCMD_CMD // CMD : command code to issue (WP = Write Page) 65 | | page << FCMD_PAGEN // PAGEN : page number 66 | | FCMD_KEY; // KEY : write protection key 67 | } 68 | 69 | void readUserPage(uint32_t data[]) { 70 | // Wait for the flash to be ready 71 | while (!isReady()); 72 | 73 | // Copy the buffer to the page buffer 74 | for (int i = 0; i < FLASH_PAGE_SIZE_WORDS; i++) { 75 | data[i] = (*(volatile uint32_t*)(USER_PAGE_BASE + i * 4)); 76 | } 77 | } 78 | 79 | void eraseUserPage() { 80 | // Wait for the flash to be ready 81 | while (!isReady()); 82 | 83 | // FCMD (Flash Command Register) : issue an Erase User Page command 84 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 85 | = FCMD_CMD_EUP << FCMD_CMD // CMD : command code to issue (EUP = Erase User Page) 86 | | FCMD_KEY; // KEY : write protection key 87 | } 88 | 89 | void writeUserPage(const uint32_t data[]) { 90 | // The flash technology only allows 1-to-0 transitions, so the 91 | // page and the buffer must first be cleared (set to 1) 92 | eraseUserPage(); 93 | clearPageBuffer(); 94 | 95 | // Wait for the flash to be ready 96 | while (!isReady()); 97 | 98 | // Copy the buffer to the page buffer 99 | for (int i = 0; i < FLASH_PAGE_SIZE_WORDS; i++) { 100 | (*(volatile uint32_t*)(USER_PAGE_BASE + i * 4)) = data[i]; 101 | } 102 | 103 | // FCMD (Flash Command Register) : issue a Write User Page command 104 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 105 | = FCMD_CMD_WUP << FCMD_CMD // CMD : command code to issue (WUP = Write User Page) 106 | | FCMD_KEY; // KEY : write protection key 107 | } 108 | 109 | void writeFuse(Fuse fuse, bool state) { 110 | // Wait for the flash to be ready 111 | while (!isReady()); 112 | 113 | // Check the fuse number 114 | if (fuse > N_FUSES) { 115 | return; 116 | } 117 | 118 | // The usable fuses are actually between 16 and 31, because the first 16 bits are lock bits 119 | fuse += 16; 120 | 121 | // FCMD (Flash Command Register) : issue a Write User Page command 122 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 123 | = (state ? FCMD_CMD_WGPB : FCMD_CMD_EGPB) << FCMD_CMD // CMD : command code to issue (WGPB = Write General Purpose Bit) 124 | | fuse << FCMD_PAGEN // PAGEN : fuse number 125 | | FCMD_KEY; // KEY : write protection key 126 | } 127 | 128 | bool getFuse(Fuse fuse) { 129 | // Wait for the flash to be ready 130 | while (!isReady()); 131 | 132 | // Check the fuse number 133 | if (fuse > N_FUSES) { 134 | return false; 135 | } 136 | 137 | // The usable fuses are actually between 16 and 31, because the first 16 bits are lock bits 138 | fuse += 16; 139 | bool high = false; 140 | if (fuse >= 32) { 141 | high = true; 142 | fuse -= 32; 143 | } 144 | 145 | return !(((*(volatile uint32_t*)(FLASH_BASE + (high ? OFFSET_FGPFRHI : OFFSET_FGPFRLO))) >> fuse) & 0x01); 146 | } 147 | 148 | void enableHighSpeedMode() { 149 | // FCMD (Flash Command Register) : issue a High Speed Enable command 150 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 151 | = FCMD_CMD_HSEN << FCMD_CMD // CMD : command code to issue (HSEN = High Speed Enable) 152 | | FCMD_KEY; // KEY : write protection key 153 | 154 | // Wait untile HS mode is enabled 155 | while (!((*(volatile uint32_t*)(FLASH_BASE + OFFSET_FSR)) & (1 << FSR_HSMODE))); 156 | } 157 | 158 | void disableHighSpeedMode() { 159 | // FCMD (Flash Command Register) : issue a High Speed Disable command 160 | (*(volatile uint32_t*)(FLASH_BASE + OFFSET_FCMD)) 161 | = FCMD_CMD_HSDIS << FCMD_CMD // CMD : command code to issue (HSEN = High Speed Disable) 162 | | FCMD_KEY; // KEY : write protection key 163 | } 164 | 165 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/dac.cpp: -------------------------------------------------------------------------------- 1 | #include "dac.h" 2 | #include "pm.h" 3 | #include "dma.h" 4 | 5 | namespace DAC { 6 | 7 | // Package-dependant, defined in pins_sam4l_XX.cpp 8 | extern struct GPIO::Pin PIN_VOUT; 9 | 10 | bool _enabled = false; 11 | int _dmaChannel = 0; 12 | 13 | // Enable the DAC controller 14 | void enable() { 15 | // Enable the clock 16 | PM::enablePeripheralClock(PM::CLK_DAC); 17 | 18 | // Set the pin in peripheral mode 19 | GPIO::enablePeripheral(PIN_VOUT); 20 | 21 | // CR (Control Register) : issue a software reset 22 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_CR)) 23 | = 1 << CR_SWRST; 24 | 25 | // WPMR (Write Protect Mode Register) : unlock the MR register 26 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_WPMR)) 27 | = WPMR_WPKEY 28 | | 0 << WPMR_WPEN; 29 | 30 | // MR (Mode Register) : setup and enable the DAC 31 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_MR)) 32 | = 0 << MR_TRGEN // TRGEN : internal trigger 33 | | 1 << MR_DACEN // DACEN : enable DAC 34 | | 0 << MR_WORD // WORD : half-word transfer 35 | | 100 << MR_STARTUP // STARTUP : startup time ~12µs 36 | | 0 << MR_CLKDIV; // CLKDIV : clock divider for internal trigger 37 | 38 | // WPMR (Write Protect Mode Register) : lock the MR register 39 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_WPMR)) 40 | = WPMR_WPKEY 41 | | 1 << WPMR_WPEN; 42 | 43 | _dmaChannel = DMA::newChannel(DMA::Device::DAC, DMA::Size::HALFWORD); 44 | 45 | _enabled = true; 46 | } 47 | 48 | // Disable the DAC controller and free ressources 49 | void disable() { 50 | // WPMR (Write Protect Mode Register) : unlock the MR register 51 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_WPMR)) 52 | = WPMR_WPKEY 53 | | 0 << WPMR_WPEN; 54 | 55 | // MR (Mode Register) : disable the DAC 56 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_MR)) = 0; 57 | 58 | // Free the pin 59 | GPIO::disablePeripheral(PIN_VOUT); 60 | 61 | // Disable the clock 62 | PM::disablePeripheralClock(PM::CLK_DAC); 63 | } 64 | 65 | void write(uint16_t value) { 66 | // Enable the DAC controller if it is not already 67 | if (!_enabled) { 68 | enable(); 69 | } 70 | 71 | // Cut high values 72 | if (value > 1023) { 73 | value = 1023; 74 | } 75 | 76 | // CDR (Conversion Data Register) : write new value 77 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_CDR)) = value; 78 | } 79 | 80 | void start(uint16_t* buffer, int n, bool repeat) { 81 | // Enable the DAC controller if it is not already 82 | if (!_enabled) { 83 | enable(); 84 | } 85 | 86 | // Stop any previous operation 87 | DMA::stopChannel(_dmaChannel); 88 | 89 | if (!repeat) { 90 | // Disable the ring mode of the DMA channel 91 | DMA::disableRing(_dmaChannel); 92 | 93 | // Start a new operation 94 | DMA::startChannel(_dmaChannel, (uint32_t)buffer, n); 95 | 96 | } else { 97 | // Enable the ring mode of the DMA channel 98 | DMA::enableRing(_dmaChannel); 99 | 100 | // Start a new operation 101 | DMA::startChannel(_dmaChannel, (uint32_t)buffer, n); 102 | 103 | // Reload the DMA channel with the same buffer, which 104 | // will be repeated indefinitely 105 | DMA::reloadChannel(_dmaChannel, (uint32_t)buffer, n); 106 | } 107 | } 108 | 109 | void reload(uint16_t* buffer, int n) { 110 | // Enable the DAC controller if it is not already 111 | if (!_enabled) { 112 | enable(); 113 | } 114 | 115 | // Reload the DMA 116 | DMA::reloadChannel(_dmaChannel, (uint32_t)buffer, n); 117 | } 118 | 119 | void stop() { 120 | // Enable the DAC controller if it is not already 121 | if (!_enabled) { 122 | enable(); 123 | } 124 | 125 | // Stop the DMA 126 | DMA::stopChannel(_dmaChannel); 127 | } 128 | 129 | bool isFinished() { 130 | // Enable the DAC controller if it is not already 131 | if (!_enabled) { 132 | enable(); 133 | } 134 | 135 | return DMA::isFinished(_dmaChannel); 136 | } 137 | 138 | bool isReloadEmpty() { 139 | // Enable the DAC controller if it is not already 140 | if (!_enabled) { 141 | enable(); 142 | } 143 | 144 | return DMA::isReloadEmpty(_dmaChannel); 145 | } 146 | 147 | bool setFrequency(unsigned long frequency) { 148 | // Enable the DAC controller if it is not already 149 | if (!_enabled) { 150 | enable(); 151 | } 152 | 153 | // Compute the clock divider for the internal trigger 154 | if (frequency == 0) { 155 | return false; 156 | } 157 | unsigned long clkdiv = PM::getModuleClockFrequency(PM::CLK_DAC) / frequency; 158 | if (clkdiv > 0xFFFF) { 159 | return false; 160 | } 161 | 162 | // WPMR (Write Protect Mode Register) : unlock the MR register 163 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_WPMR)) 164 | = WPMR_WPKEY 165 | | 0 << WPMR_WPEN; 166 | 167 | // MR (Mode Register) : update CLKDIV 168 | uint32_t mr = (*(volatile uint32_t*)(DAC_BASE + OFFSET_MR)); 169 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_MR)) 170 | = (mr & 0x0000FFFF) 171 | | clkdiv << MR_CLKDIV; 172 | 173 | // WPMR (Write Protect Mode Register) : lock the MR register 174 | (*(volatile uint32_t*)(DAC_BASE + OFFSET_WPMR)) 175 | = WPMR_WPKEY 176 | | 1 << WPMR_WPEN; 177 | 178 | return true; 179 | } 180 | 181 | void enableInterrupt(void (*handler)(), Interrupt interrupt) { 182 | // Enable the DAC controller if it is not already 183 | if (!_enabled) { 184 | enable(); 185 | } 186 | 187 | // Enable the interrupt directly in the DMA 188 | DMA::enableInterrupt(_dmaChannel, handler, static_cast(interrupt)); 189 | } 190 | 191 | void disableInterrupt(Interrupt interrupt) { 192 | // Enable the DAC controller if it is not already 193 | if (!_enabled) { 194 | enable(); 195 | } 196 | 197 | // Disable the interrupt in the DMA 198 | DMA::disableInterrupt(_dmaChannel, static_cast(interrupt)); 199 | } 200 | 201 | void setPin(GPIO::Pin pin) { 202 | PIN_VOUT = pin; 203 | } 204 | 205 | } -------------------------------------------------------------------------------- /libtungsten/utils/RingBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "RingBuffer.h" 2 | #include 3 | 4 | // Constructor : must be passed the buffer to use 5 | RingBuffer::RingBuffer(uint8_t* buffer, unsigned int capacity) { 6 | _buffer = buffer; 7 | _capacity = capacity; 8 | _cursorR = 0; 9 | _cursorW = 0; 10 | _empty = true; 11 | _overflow = false; 12 | _underflow = false; 13 | } 14 | 15 | // Get the value of a random byte in the buffer, without 16 | // changing the cursors 17 | uint8_t RingBuffer::operator[](unsigned int i) const { 18 | if (i >= size()) { 19 | return 0; 20 | } else { 21 | if (_cursorR + i < _capacity) { 22 | return _buffer[_cursorR + i]; 23 | } else { 24 | return _buffer[_cursorR + i - _capacity]; 25 | } 26 | } 27 | } 28 | 29 | // Read one byte from the internal buffer 30 | uint8_t RingBuffer::read() { 31 | if (_empty) { 32 | _underflow = true; 33 | return 0; 34 | } 35 | 36 | // Clear overflow status 37 | _overflow = false; 38 | 39 | // Get the next byte and move the cursor 40 | uint8_t byte = _buffer[_cursorR]; 41 | _cursorR++; 42 | if (_cursorR >= _capacity) { 43 | _cursorR = 0; 44 | } 45 | if (_cursorR == _cursorW) { 46 | _empty = true; 47 | } 48 | return byte; 49 | } 50 | 51 | // Read some bytes from the internal buffer 52 | int RingBuffer::read(uint8_t* buffer, unsigned int size) { 53 | if (size == 0) { 54 | return 0; 55 | } 56 | 57 | // If the internal buffer is empty, return immediately 58 | if (_empty) { 59 | _underflow = true; 60 | return 0; 61 | } 62 | 63 | // Clear overflow status 64 | _overflow = false; 65 | 66 | // If the requested number of bytes is greater than the 67 | // current size, read only what is available and set the 68 | // underflow flag 69 | unsigned int s = RingBuffer::size(); 70 | if (s < size) { 71 | size = s; 72 | _underflow = true; 73 | } 74 | 75 | // Copy data to the user buffer 76 | if (_cursorR + size <= _capacity) { 77 | memcpy(buffer, _buffer + _cursorR, size); 78 | _cursorR += size; 79 | 80 | } else { 81 | unsigned int size2 = _capacity - _cursorR; 82 | if (size2 > 0) { 83 | memcpy(buffer, _buffer + _cursorR, size2); 84 | } 85 | if (size - size2 > 0) { 86 | memcpy(buffer + size2, _buffer, size - size2); 87 | } 88 | _cursorR = size - size2; 89 | } 90 | if (_cursorR == _cursorW) { 91 | _empty = true; 92 | } 93 | 94 | // Return the number of bytes that were actually read 95 | return size; 96 | } 97 | 98 | // Write one byte into the internal buffer 99 | void RingBuffer::write(uint8_t byte) { 100 | // Check for overflow 101 | if (size() + 1 > _capacity) { 102 | _overflow = true; 103 | } 104 | 105 | // Clear underflow status 106 | _underflow = false; 107 | 108 | // Copy the byte and move the cursor 109 | _buffer[_cursorW] = byte; 110 | _cursorW++; 111 | if (_cursorW >= _capacity) { 112 | _cursorW = 0; 113 | } 114 | 115 | // If the buffer is in overflow state, put the R cursor at the W cursor 116 | if (_overflow) { 117 | _cursorR = _cursorW; 118 | } 119 | 120 | _empty = false; 121 | } 122 | 123 | // Write some bytes into the internal buffer 124 | void RingBuffer::write(const uint8_t* buffer, unsigned int size) { 125 | if (size == 0) { 126 | return; 127 | } 128 | 129 | // Check for overflow 130 | if (RingBuffer::size() + size > _capacity) { 131 | _overflow = true; 132 | } 133 | 134 | // Clear underflow status 135 | _underflow = false; 136 | 137 | // Copy data into the internal buffer 138 | if (_cursorW + size <= _capacity) { 139 | memcpy(_buffer + _cursorW, buffer, size); 140 | _cursorW += size; 141 | if (_cursorW == _capacity) { 142 | _cursorW = 0; 143 | } 144 | 145 | } else { 146 | // If the given size is larger than the capacity, keep only the last bytes 147 | unsigned int bufferOffset = 0; 148 | if (size > _capacity) { 149 | bufferOffset = size - _capacity; 150 | size = _capacity; 151 | } 152 | 153 | // Copy the first part to the end of the buffer 154 | unsigned int size2 = _capacity - _cursorW; 155 | if (size2 > 0) { 156 | memcpy(_buffer + _cursorW, buffer + bufferOffset, size2); 157 | } 158 | 159 | // Copy the last part to the beginning of the buffer 160 | if (size - size2 > 0) { 161 | memcpy(_buffer, buffer + bufferOffset + size2, size - size2); 162 | } 163 | 164 | // Move the cursor 165 | _cursorW = size - size2; 166 | } 167 | 168 | // If the buffer is in overflow state, put the R cursor at the W cursor 169 | if (_overflow) { 170 | _cursorR = _cursorW; 171 | } 172 | 173 | _empty = false; 174 | } 175 | 176 | // Number of bytes currently stored in the buffer 177 | unsigned int RingBuffer::size() const { 178 | if (_cursorW == _cursorR) { 179 | if (_empty) { 180 | return 0; 181 | } else { 182 | return _capacity; 183 | } 184 | } else if (_cursorW > _cursorR) { 185 | return _cursorW - _cursorR; 186 | } else { 187 | return _capacity - _cursorR + _cursorW; 188 | } 189 | } 190 | 191 | // Check if the specified byte is in the buffer 192 | int RingBuffer::contains(uint8_t byte) const { 193 | if (_cursorW > _cursorR) { 194 | for (unsigned int i = _cursorR; i < _cursorW; i++) { 195 | if (_buffer[i] == byte) { 196 | return i - _cursorR; 197 | } 198 | } 199 | } else if (_cursorW < _cursorR) { 200 | for (unsigned int i = _cursorR; i < _capacity; i++) { 201 | if (_buffer[i] == byte) { 202 | return i - _cursorR; 203 | } 204 | } 205 | for (unsigned int i = 0; i < _cursorW; i++) { 206 | if (_buffer[i] == byte) { 207 | return _capacity - _cursorR + i; 208 | } 209 | } 210 | } 211 | 212 | // Not found 213 | return -1; 214 | } 215 | 216 | // Internal buffer total capacity 217 | unsigned int RingBuffer::capacity() const { 218 | return _capacity; 219 | } 220 | 221 | // Return true if the internal buffer is overflown 222 | // (too many writes, not enough reads) 223 | bool RingBuffer::isOverflow() const { 224 | return _overflow; 225 | } 226 | 227 | // Return true if the user attempted to read more bytes than 228 | // were available 229 | bool RingBuffer::isUnderflow() const { 230 | return _underflow; 231 | } 232 | 233 | // Revert the ring buffer to its initial state : 234 | // cursors and overflow/underflow flags are reset 235 | void RingBuffer::reset() { 236 | _cursorR = 0; 237 | _cursorW = 0; 238 | _empty = true; 239 | _overflow = false; 240 | _underflow = false; 241 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/eic.cpp: -------------------------------------------------------------------------------- 1 | #include "eic.h" 2 | #include "pm.h" 3 | #include "bpm.h" 4 | #include "core.h" 5 | #include "gpio.h" 6 | #include "error.h" 7 | #include 8 | 9 | namespace EIC { 10 | 11 | // Package-dependant, defined in pins_sam4l_XX.cpp 12 | extern struct GPIO::Pin PINS[]; 13 | 14 | // Handlers defined by the user 15 | extern uint8_t INTERRUPT_PRIORITY; 16 | bool _initialized = false; 17 | uint32_t _interruptHandlers[N_CHANNELS - 1]; // -1 because channel 0 is the NMI 18 | 19 | // Internal functions 20 | void init(); 21 | void handlerWrapper(); 22 | 23 | 24 | void setPin(Channel channel, GPIO::Pin pin) { 25 | PINS[channel] = pin; 26 | } 27 | 28 | void init() { 29 | memset(_interruptHandlers, 0, sizeof(_interruptHandlers)); 30 | } 31 | 32 | void enableInterrupt(Channel channel, Mode mode, Polarity polarity, void (*handler)(int), bool filter) { 33 | // Init the module if necessary 34 | if (!_initialized) { 35 | init(); 36 | _initialized = true; 37 | } 38 | 39 | // Check channel number 40 | if (channel >= N_CHANNELS) { 41 | Error::happened(Error::Module::EIC, ERR_UNKNOWN_CHANNEL, Error::Severity::WARNING); 42 | return; 43 | } 44 | 45 | if (mode == Mode::EDGE) { 46 | // Mode 47 | (*(volatile uint32_t*)(BASE + OFFSET_MODE)) &= ~(uint32_t)(1 << channel); 48 | 49 | // Polarity : rising or falling edge 50 | if (polarity == Polarity::LOW_FALLING) { 51 | (*(volatile uint32_t*)(BASE + OFFSET_EDGE)) &= ~(uint32_t)(1 << channel); 52 | 53 | } else if (polarity == Polarity::HIGH_RISING) { 54 | (*(volatile uint32_t*)(BASE + OFFSET_EDGE)) |= 1 << channel; 55 | } 56 | 57 | } else if (mode == Mode::LEVEL) { 58 | // Mode 59 | (*(volatile uint32_t*)(BASE + OFFSET_MODE)) |= 1 << channel; 60 | 61 | // Polarity : high or low level 62 | if (polarity == Polarity::LOW_FALLING) { 63 | (*(volatile uint32_t*)(BASE + OFFSET_LEVEL)) &= ~(uint32_t)(1 << channel); 64 | 65 | } else if (polarity == Polarity::HIGH_RISING) { 66 | (*(volatile uint32_t*)(BASE + OFFSET_LEVEL)) |= 1 << channel; 67 | } 68 | } 69 | 70 | // Filter 71 | if (filter) { 72 | (*(volatile uint32_t*)(BASE + OFFSET_FILTER)) |= 1 << channel; 73 | } else { 74 | (*(volatile uint32_t*)(BASE + OFFSET_FILTER)) &= ~(uint32_t)(1 << channel); 75 | } 76 | 77 | // IER (Interrupt Enable Register) : enable the requested interrupt 78 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) = 1 << channel; 79 | 80 | // Set the handler and enable the module interrupt at the Core level, except for the NMI 81 | if (channel > 0) { 82 | _interruptHandlers[channel - 1] = (uint32_t)handler; 83 | Core::Interrupt interrupt = static_cast(static_cast(Core::Interrupt::EIC1) + channel - 1); 84 | Core::setInterruptHandler(interrupt, handlerWrapper); 85 | Core::enableInterrupt(interrupt, INTERRUPT_PRIORITY); 86 | } 87 | 88 | // Input pin 89 | GPIO::enablePeripheral(PINS[channel]); 90 | 91 | // EN (Enable Register) : enable the requested channel 92 | (*(volatile uint32_t*)(BASE + OFFSET_EN)) = 1 << channel; 93 | } 94 | 95 | void enableAsyncInterrupt(Channel channel, Polarity polarity, void (*handler)(int)) { 96 | // Init the module if necessary 97 | if (!_initialized) { 98 | init(); 99 | _initialized = true; 100 | } 101 | 102 | // Check channel number 103 | if (channel >= N_CHANNELS) { 104 | Error::happened(Error::Module::EIC, ERR_UNKNOWN_CHANNEL, Error::Severity::WARNING); 105 | return; 106 | } 107 | 108 | // Mode : only level in async mode 109 | (*(volatile uint32_t*)(BASE + OFFSET_MODE)) |= 1 << channel; 110 | 111 | // Polarity : high or low level 112 | if (polarity == Polarity::LOW_FALLING) { 113 | (*(volatile uint32_t*)(BASE + OFFSET_LEVEL)) &= ~(uint32_t)(1 << channel); 114 | 115 | } else if (polarity == Polarity::HIGH_RISING) { 116 | (*(volatile uint32_t*)(BASE + OFFSET_LEVEL)) |= 1 << channel; 117 | } 118 | 119 | // Filter disabled in async mode 120 | (*(volatile uint32_t*)(BASE + OFFSET_FILTER)) &= ~(uint32_t)(1 << channel); 121 | 122 | // IER (Interrupt Enable Register) : enable the requested interrupt 123 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) = 1 << channel; 124 | 125 | // Set the handler and enable the module interrupt at the Core level, except for the NMI 126 | if (channel > 0) { 127 | _interruptHandlers[channel - 1] = (uint32_t)handler; 128 | Core::Interrupt interrupt = static_cast(static_cast(Core::Interrupt::EIC1) + channel - 1); 129 | Core::setInterruptHandler(interrupt, handlerWrapper); 130 | Core::enableInterrupt(interrupt, INTERRUPT_PRIORITY); 131 | } 132 | 133 | // Wake up logic 134 | BPM::enableBackupWakeUpSource(BPM::BackupWakeUpSource::EIC); 135 | 136 | // Input pin 137 | GPIO::enablePeripheral(PINS[channel]); 138 | BPM::enableBackupPin(static_cast(channel)); 139 | 140 | // EN (Enable Register) : enable the requested channel 141 | (*(volatile uint32_t*)(BASE + OFFSET_EN)) = 1 << channel; 142 | } 143 | 144 | void disableInterrupt(Channel channel) { 145 | // Check channel number 146 | if (channel >= N_CHANNELS) { 147 | Error::happened(Error::Module::EIC, ERR_UNKNOWN_CHANNEL, Error::Severity::WARNING); 148 | return; 149 | } 150 | 151 | // IDR (Interrupt Disable Register) : disable the requested interrupt 152 | (*(volatile uint32_t*)(BASE + OFFSET_IDR)) = 1 << channel; 153 | 154 | // DIS (Disable Register) : disable the requested channel 155 | (*(volatile uint32_t*)(BASE + OFFSET_DIS)) = 1 << channel; 156 | 157 | // Free the input pin 158 | GPIO::disablePeripheral(PINS[channel]); 159 | } 160 | 161 | void clearInterrupt(Channel channel) { 162 | // Check channel number 163 | if (channel >= N_CHANNELS) { 164 | Error::happened(Error::Module::EIC, ERR_UNKNOWN_CHANNEL, Error::Severity::WARNING); 165 | return; 166 | } 167 | 168 | // ICR (Interrupt Clear Register) : clear the interrupt 169 | (*(volatile uint32_t*)(BASE + OFFSET_ICR)) = 1 << channel; 170 | } 171 | 172 | // This wrapper is called when an interrupt is triggered and is used to clear the interrupt 173 | // and call a user handler if defined 174 | void handlerWrapper() { 175 | // Channel that triggered the interrupt 176 | int channel = static_cast(Core::currentInterrupt()) - static_cast(Core::Interrupt::EIC1) + 1; 177 | 178 | // Call the user handler for this interrupt 179 | void (*handler)(int) = (void (*)(int))_interruptHandlers[channel - 1]; 180 | if (handler != nullptr) { 181 | handler(channel); 182 | } 183 | 184 | // ICR (Interrupt Clear Register) : clear the interrupt that was triggered 185 | (*(volatile uint32_t*)(BASE + OFFSET_ICR)) = 1 << channel; 186 | } 187 | 188 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/adc.cpp: -------------------------------------------------------------------------------- 1 | #include "adc.h" 2 | #include "pm.h" 3 | 4 | namespace ADC { 5 | 6 | // Package-dependant, defined in pins_sam4l_XX.cpp 7 | extern struct GPIO::Pin PINS[]; 8 | 9 | // Bitset representing enabled channels 10 | uint16_t _enabledChannels = 0x0000; 11 | 12 | // Keep track of the state of the module 13 | bool _initialized = false; 14 | 15 | // Analog reference selected by the user 16 | AnalogReference _analogReference = AnalogReference::INTERNAL_1V; 17 | 18 | // Reference voltage value in mV 19 | // For VCC_0625 and VCC_OVER_2, this is simply the Vcc voltage 20 | int _vref = 0; 21 | 22 | 23 | // Initialize the common ressources of the ADC controller 24 | void init(AnalogReference analogReference, int vref) { 25 | // Voltage reference 26 | if (analogReference == AnalogReference::INTERNAL_1V) { 27 | vref = 1000; 28 | } 29 | _analogReference = analogReference; 30 | _vref = vref; 31 | 32 | // Enable the clock 33 | PM::enablePeripheralClock(PM::CLK_ADC); 34 | 35 | // Find a prescaler setting that will bring the module clock frequency below 36 | // the maximum specified in the datasheet (42.9.4 Analog to Digital Converter 37 | // Characteristics - ADC clock frequency - Max : 1.5MHz). 38 | // A frequency too high may otherwise result in incorrect conversions. 39 | unsigned long frequency = PM::getModuleClockFrequency(PM::CLK_ADC); 40 | uint8_t prescal = 0; 41 | for (prescal = 0b000; prescal <= 0b111; prescal++) { 42 | if ((frequency >> (prescal + 2)) <= 1500000) { // 1.5MHz 43 | break; 44 | } 45 | } 46 | 47 | // CR (Control Register) : enable the ADC 48 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_CR)) 49 | = 1 << CR_EN // EN : enable ADC 50 | | 1 << CR_REFBUFEN // REFBUFEN : enable reference buffer 51 | | 1 << CR_BGREQEN; // BGREQEN : enable bandgap voltage reference 52 | 53 | // CFG (Configuration Register) : set general settings 54 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_CFG)) 55 | = static_cast(analogReference) << CFG_REFSEL // REFSEL : voltage reference 56 | | 0b11 << CFG_SPEED // SPEED : 75ksps 57 | | 1 << CFG_CLKSEL // CLKSEL : use APB clock 58 | | prescal << CFG_PRESCAL; // PRESCAL : divide clock by 4 59 | 60 | // SR (Status Register) : wait for enabled status flag 61 | while (!((*(volatile uint32_t*)(ADC_BASE + OFFSET_SR)) & (1 << SR_EN))); 62 | 63 | // Update the module status 64 | _initialized = true; 65 | } 66 | 67 | void enable(Channel channel) { 68 | // Set the pin in peripheral mode 69 | GPIO::enablePeripheral(PINS[channel]); 70 | 71 | // Initialize and enable the ADC controller if necessary 72 | if (!_initialized) { 73 | init(); 74 | } 75 | _enabledChannels |= 1 << channel; 76 | } 77 | 78 | void disable(Channel channel) { 79 | // Disable the peripheral mode on the pin 80 | GPIO::disablePeripheral(PINS[channel]); 81 | 82 | // Disable the ADC controller if necessary 83 | _enabledChannels &= ~(uint32_t)(1 << channel); 84 | if (_enabledChannels == 0x0000) { 85 | // CR (Control Register) : disable the ADC 86 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_CR)) 87 | = 1 << CR_DIS; // DIS : disable ADC 88 | _initialized = false; 89 | } 90 | } 91 | 92 | // Read the current raw value measured by the ADC on the given channel 93 | uint16_t readRaw(Channel channel, Gain gain, Channel relativeTo) { 94 | // Enable the channels if they are not already 95 | if (!(_enabledChannels & 1 << channel)) { 96 | enable(channel); 97 | } 98 | if (relativeTo != 0xFF && !(_enabledChannels & 1 << relativeTo)) { 99 | enable(relativeTo); 100 | } 101 | 102 | // SEQCFG (Sequencer Configuration Register) : setup the conversion 103 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_SEQCFG)) 104 | = 0 << SEQCFG_HWLA // HWLA : Half Word Left Adjust disabled 105 | | (relativeTo != 0xFF) << SEQCFG_BIPOLAR // BIPOLAR : single-ended or bipolar mode 106 | | static_cast(gain) << SEQCFG_GAIN // GAIN : user-selected gain 107 | | 1 << SEQCFG_GCOMP // GCOMP : gain error reduction enabled 108 | | 0b000 << SEQCFG_TRGSEL // TRGSEL : software trigger 109 | | 0 << SEQCFG_RES // RES : 12-bit resolution 110 | | (relativeTo != 0xFF ? 0b00 : 0b10) << SEQCFG_INTERNAL // INTERNAL : POS external, NEG internal or external 111 | | (channel & 0b1111) << SEQCFG_MUXPOS // MUXPOS : selected channel 112 | | (relativeTo != 0xFF ? relativeTo & 0b111 : 0b111) << SEQCFG_MUXNEG // MUXNEG : pad ground or neg channel 113 | | 0b000 << SEQCFG_ZOOMRANGE; // ZOOMRANGE : default 114 | 115 | // CR (Control Register) : start conversion 116 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_CR)) 117 | = 1 << CR_STRIG; // STRIG : Sequencer Trigger 118 | 119 | // SR (Status Register) : wait for Sequencer End Of Conversion status flag 120 | while (!((*(volatile uint32_t*)(ADC_BASE + OFFSET_SR)) & (1 << SR_SEOC))); 121 | 122 | // SCR (Status Clear Register) : clear Sequencer End Of Conversion status flag 123 | (*(volatile uint32_t*)(ADC_BASE + OFFSET_SCR)) = 1 << SR_SEOC; 124 | 125 | // LCV (Last Converted Value) : conversion result 126 | return (*(volatile uint32_t*)(ADC_BASE + OFFSET_LCV)) & 0xFFFF; 127 | } 128 | 129 | // Return the current value on the given channel in mV 130 | int read(Channel channel, Gain gain, Channel relativeTo) { 131 | int value = readRaw(channel, gain, relativeTo); 132 | 133 | // Compute reference 134 | int vref = _vref; 135 | if (_analogReference == AnalogReference::VCC_0625) { 136 | vref = (vref * 625) / 1000; 137 | } else if (_analogReference == AnalogReference::VCC_OVER_2) { 138 | vref = vref / 2; 139 | } else if (_analogReference == AnalogReference::INTERNAL_1V) { 140 | vref = 1000; 141 | } 142 | 143 | // Convert the result to mV 144 | // Single-ended : value = gain * voltage / ref * 4095 <=> voltage = value * ref / (gain * 4095) 145 | // Differential : value = 2047 + gain * voltage / ref * 2047 <=> voltage = (value - 2047) * ref / (gain * 2047) 146 | if (relativeTo != 0xFF) { 147 | value -= 2047; 148 | } 149 | int gainCoefficients[] = {1, 2, 4, 8, 16, 32, 64}; 150 | if (gain == Gain::X05) { 151 | value *= 2; 152 | } 153 | value *= vref; 154 | if (relativeTo != 0xFF) { 155 | value /= 2047; 156 | } else { 157 | value /= 4095; 158 | } 159 | if (gain != Gain::X05) { 160 | value /= gainCoefficients[static_cast(gain)]; 161 | } 162 | 163 | return value; 164 | } 165 | 166 | void setPin(Channel channel, GPIO::Pin pin) { 167 | PINS[channel] = pin; 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/pins_sam4l_48.cpp: -------------------------------------------------------------------------------- 1 | #include "scif.h" 2 | #include "gpio.h" 3 | #include "usb.h" 4 | #include "usart.h" 5 | #include "adc.h" 6 | #include "dac.h" 7 | #include "tc.h" 8 | #include "i2c.h" 9 | #include "spi.h" 10 | #include "gloc.h" 11 | #include "eic.h" 12 | 13 | // This file defines the default pin mapping for peripherals. 14 | // Most of the chip peripherals can map their signals on a few different 15 | // pins. The list of available functions for each pin is defined in the 16 | // datasheet, §3.2.1 Multiplexed Signals. Use the setPin() functions of 17 | // each module to modify the default mapping. 18 | 19 | namespace ADC { 20 | 21 | GPIO::Pin PINS[] = { 22 | {GPIO::Port::A, 4, GPIO::Periph::A}, // ADC0 23 | {GPIO::Port::A, 5, GPIO::Periph::A}, // ADC1 24 | {GPIO::Port::A, 7, GPIO::Periph::A}, // ADC2 25 | }; 26 | 27 | } 28 | 29 | namespace DAC { 30 | 31 | GPIO::Pin PIN_VOUT = {GPIO::Port::A, 6, GPIO::Periph::A}; 32 | 33 | } 34 | 35 | namespace EIC { 36 | 37 | GPIO::Pin PINS[] = { 38 | {}, // EXTINT0/NMI isn't available on this package 39 | {GPIO::Port::A, 6, GPIO::Periph::C}, // EXTINT1 40 | {GPIO::Port::A, 4, GPIO::Periph::C}, // EXTINT2 41 | {GPIO::Port::A, 5, GPIO::Periph::C}, // EXTINT3 42 | {GPIO::Port::A, 7, GPIO::Periph::C}, // EXTINT4 43 | {GPIO::Port::A, 20, GPIO::Periph::C}, // EXTINT5 44 | {GPIO::Port::A, 21, GPIO::Periph::C}, // EXTINT6 45 | {GPIO::Port::A, 22, GPIO::Periph::C}, // EXTINT7 46 | {GPIO::Port::A, 23, GPIO::Periph::C}, // EXTINT8 47 | }; 48 | 49 | // Alternatives 50 | //{GPIO::Port::A, 16, GPIO::Periph::C}, // EXTINT1 51 | //{GPIO::Port::A, 17, GPIO::Periph::C}, // EXTINT2 52 | //{GPIO::Port::A, 18, GPIO::Periph::C}, // EXTINT3 53 | //{GPIO::Port::A, 19, GPIO::Periph::C}, // EXTINT4 54 | 55 | } 56 | 57 | namespace GLOC { 58 | 59 | GPIO::Pin PINS_IN[][4] = { 60 | { 61 | {GPIO::Port::A, 6, GPIO::Periph::D}, // GLOC0 IN0 62 | {GPIO::Port::A, 4, GPIO::Periph::D}, // GLOC0 IN1 63 | {GPIO::Port::A, 5, GPIO::Periph::D}, // GLOC0 IN2 64 | {GPIO::Port::A, 7, GPIO::Periph::D} // GLOC0 IN3 65 | }, 66 | { 67 | {GPIO::Port::A, 27, GPIO::Periph::D}, // GLOC1 IN4 68 | {GPIO::Port::A, 28, GPIO::Periph::D}, // GLOC1 IN5 69 | {GPIO::Port::A, 29, GPIO::Periph::D}, // GLOC1 IN6 70 | {GPIO::Port::A, 30, GPIO::Periph::D} // GLOC1 IN7 71 | } 72 | }; 73 | 74 | GPIO::Pin PINS_OUT[] = { 75 | {GPIO::Port::A, 8, GPIO::Periph::D}, // GLOC0 OUT 76 | {GPIO::Port::A, 31, GPIO::Periph::D} // GLOC1 OUT 77 | }; 78 | 79 | // Alternatives for GLOC0 80 | //{GPIO::Port::A, 20, GPIO::Periph::D}, // GLOC0 IN0 81 | //{GPIO::Port::A, 21, GPIO::Periph::D}, // GLOC0 IN1 82 | //{GPIO::Port::A, 22, GPIO::Periph::D}, // GLOC0 IN2 83 | //{GPIO::Port::A, 23, GPIO::Periph::D} // GLOC0 IN3 84 | //{GPIO::Port::A, 24, GPIO::Periph::D}, // GLOC0 OUT 85 | 86 | } 87 | 88 | namespace I2C { 89 | 90 | // SDA 91 | GPIO::Pin PINS_SDA[] = { 92 | {GPIO::Port::A, 23, GPIO::Periph::B}, // I2C0 SDA 93 | {}, // I2C1 isn't available on this packages 94 | {GPIO::Port::A, 21, GPIO::Periph::E}, // I2C2 SDA 95 | }; 96 | 97 | // SCL 98 | GPIO::Pin PINS_SCL[] = { 99 | {GPIO::Port::A, 24, GPIO::Periph::B}, // I2C0 SCL 100 | {}, // I2C1 isn't available on this packages 101 | {GPIO::Port::A, 22, GPIO::Periph::E}, // I2C2 SCL 102 | }; 103 | 104 | } 105 | 106 | namespace SCIF { 107 | 108 | GPIO::Pin PINS_GCLK[] = { 109 | {GPIO::Port::A, 19, GPIO::Periph::E}, // GCLK0 110 | {GPIO::Port::A, 20, GPIO::Periph::E}, // GCLK1 111 | }; 112 | 113 | GPIO::Pin PINS_GCLK_IN[] = { 114 | {GPIO::Port::A, 23, GPIO::Periph::E}, // GCLK_IN0 115 | {GPIO::Port::A, 24, GPIO::Periph::E} // GCLK_IN1 116 | }; 117 | 118 | // Alternatives for GCLK0 119 | //{GPIO::Port::A, 2, GPIO::Periph::A} 120 | } 121 | 122 | namespace SPI { 123 | 124 | GPIO::Pin PIN_MISO = {GPIO::Port::A, 27, GPIO::Periph::A}; 125 | GPIO::Pin PIN_MOSI = {GPIO::Port::A, 28, GPIO::Periph::A}; 126 | GPIO::Pin PIN_SCK = {GPIO::Port::A, 29, GPIO::Periph::A}; 127 | GPIO::Pin PIN_NPCS0 = {GPIO::Port::A, 30, GPIO::Periph::A}; 128 | GPIO::Pin PIN_NPCS1 = {GPIO::Port::A, 31, GPIO::Periph::A}; 129 | GPIO::Pin PIN_NPCS2 = {GPIO::Port::A, 14, GPIO::Periph::C}; 130 | GPIO::Pin PIN_NPCS3 = {GPIO::Port::A, 15, GPIO::Periph::C}; 131 | 132 | // Alternatives for MISO 133 | //const GPIO::Pin PIN_MISO = {GPIO::Port::A, 3, GPIO::Periph::B}; 134 | //const GPIO::Pin PIN_MISO = {GPIO::Port::A, 21, GPIO::Periph::A}; 135 | 136 | // Alternatives for MOSI 137 | //const GPIO::Pin PIN_MOSI = {GPIO::Port::A, 22, GPIO::Periph::A}; 138 | 139 | // Alternatives for SCK 140 | //const GPIO::Pin PIN_SCK = {GPIO::Port::A, 23, GPIO::Periph::A}; 141 | 142 | // Alternatives for NPCS0 143 | //const GPIO::Pin PIN_NPCS0 = {GPIO::Port::A, 2, GPIO::Periph::B}; 144 | //const GPIO::Pin PIN_NPCS0 = {GPIO::Port::A, 24, GPIO::Periph::A}; 145 | 146 | // Alternatives for NPCS1 147 | //const GPIO::Pin PIN_NPCS1 = {GPIO::Port::A, 13, GPIO::Periph::C}; 148 | 149 | // No alternatives for NPCS2 ou NPCS3 150 | 151 | } 152 | 153 | namespace TC { 154 | 155 | const uint8_t N_TC = 1; 156 | 157 | GPIO::Pin PINS[MAX_N_TC][N_COUNTERS_PER_TC * N_CHANNELS_PER_COUNTER] = { 158 | { 159 | {GPIO::Port::A, 8, GPIO::Periph::B}, // TC0 A0 160 | {GPIO::Port::A, 9, GPIO::Periph::B}, // TC0 B0 161 | {GPIO::Port::A, 10, GPIO::Periph::B}, // TC0 A1 162 | {GPIO::Port::A, 11, GPIO::Periph::B}, // TC0 B1 163 | {GPIO::Port::A, 12, GPIO::Periph::B}, // TC0 A2 164 | {GPIO::Port::A, 13, GPIO::Periph::B} // TC0 B2 165 | } 166 | }; 167 | 168 | GPIO::Pin PINS_CLK[MAX_N_TC][N_EXTERNAL_CLOCKS_PER_TC] = { 169 | { 170 | {GPIO::Port::A, 14, GPIO::Periph::B}, // TC0 CLK0 171 | {GPIO::Port::A, 15, GPIO::Periph::B}, // TC0 CLK1 172 | {GPIO::Port::A, 16, GPIO::Periph::B}, // TC0 CLK2 173 | } 174 | }; 175 | 176 | } 177 | 178 | namespace USART { 179 | 180 | // RX 181 | GPIO::Pin PINS_RX[] = { 182 | {GPIO::Port::A, 11, GPIO::Periph::A}, // USART0 RX 183 | {GPIO::Port::A, 15, GPIO::Periph::A}, // USART1 RX 184 | {GPIO::Port::A, 19, GPIO::Periph::A}, // USART2 RX 185 | {GPIO::Port::A, 30, GPIO::Periph::E} // USART3 RX 186 | }; 187 | 188 | // TX 189 | GPIO::Pin PINS_TX[] = { 190 | {GPIO::Port::A, 12, GPIO::Periph::A}, // USART0 TX 191 | {GPIO::Port::A, 16, GPIO::Periph::A}, // USART1 TX 192 | {GPIO::Port::A, 20, GPIO::Periph::A}, // USART2 TX 193 | {GPIO::Port::A, 31, GPIO::Periph::E} // USART3 TX 194 | }; 195 | 196 | // RTS 197 | GPIO::Pin PINS_RTS[] = { 198 | {GPIO::Port::A, 8, GPIO::Periph::A}, // USART0 RTS 199 | {GPIO::Port::A, 13, GPIO::Periph::A}, // USART1 RTS 200 | {GPIO::Port::A, 17, GPIO::Periph::A}, // USART2 RTS 201 | {GPIO::Port::A, 27, GPIO::Periph::E} // USART3 RTS 202 | }; 203 | 204 | // CTS 205 | GPIO::Pin PINS_CTS[] = { 206 | {GPIO::Port::A, 9, GPIO::Periph::A}, // USART0 CTS 207 | {GPIO::Port::A, 21, GPIO::Periph::B}, // USART1 CTS 208 | {GPIO::Port::A, 22, GPIO::Periph::B}, // USART2 CTS 209 | {GPIO::Port::A, 28, GPIO::Periph::E} // USART3 CTS 210 | }; 211 | 212 | 213 | // Alternatives for USART0 214 | // Be careful when using these pins that they are not already used for something else 215 | 216 | //{GPIO::Port::A, 5, GPIO::Periph::B} // RX 217 | //{GPIO::Port::A, 7, GPIO::Periph::B} // TX 218 | //{GPIO::Port::A, 6, GPIO::Periph::B} // RTS 219 | 220 | 221 | // Alternatives for USART2 222 | 223 | //{GPIO::Port::A, 25, GPIO::Periph::B} // RX 224 | //{GPIO::Port::A, 26, GPIO::Periph::B} // TX 225 | 226 | } 227 | 228 | namespace USB { 229 | 230 | const GPIO::Pin PIN_DM = {GPIO::Port::A, 25, GPIO::Periph::A}; 231 | const GPIO::Pin PIN_DP = {GPIO::Port::A, 26, GPIO::Periph::A}; 232 | 233 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/bpm.cpp: -------------------------------------------------------------------------------- 1 | #include "bpm.h" 2 | #include "pm.h" 3 | #include "eic.h" 4 | #include "flash.h" 5 | #include "error.h" 6 | 7 | namespace BPM { 8 | 9 | // Current power scaling setting 10 | PowerScaling _currentPS = PowerScaling::PS0; 11 | 12 | // Interrupt handlers 13 | extern uint8_t INTERRUPT_PRIORITY; 14 | uint32_t _interruptHandlers[N_INTERRUPTS]; 15 | const int _interruptBits[N_INTERRUPTS] = {SR_PSOK}; 16 | void interruptHandlerWrapper(); 17 | 18 | void setPowerScaling(PowerScaling ps) { 19 | Core::stashInterrupts(); 20 | 21 | // Enable Flash High Speed mode if entering PS2 22 | if (ps == PowerScaling::PS2) { 23 | Flash::enableHighSpeedMode(); 24 | } 25 | 26 | // Get the value of PMCON without PS 27 | uint32_t pmcon = (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) & ~(uint32_t)(0b11 << PMCON_PS); 28 | 29 | // Unlock the PMCON register, which is locked by default as a safety mesure 30 | (*(volatile uint32_t*)(BASE + OFFSET_UNLOCK)) 31 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 32 | | OFFSET_PMCON; // ADDR : unlock PMCON 33 | 34 | // Select the power scaling register and request a Power Scaling Change 35 | (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) 36 | = pmcon 37 | | static_cast(ps) << PMCON_PS // PS : select Power Scaling mode 38 | | 1 << PMCON_PSCREQ // PSCREQ : Power Scaling Change Request 39 | | 1 << PMCON_PSCM; // PSCM : Power Scaling Change Request 40 | 41 | // Wait for the Power Scaling OK flag 42 | while (!(*(volatile uint32_t*)(BASE + OFFSET_SR) & (1 << SR_PSOK))); 43 | 44 | // Disable Flash High Speed mode if exiting PS2 45 | if (_currentPS == PowerScaling::PS2) { 46 | Flash::disableHighSpeedMode(); 47 | } 48 | 49 | // Save the current setting 50 | _currentPS = ps; 51 | 52 | Core::applyStashedInterrupts(); 53 | } 54 | 55 | PowerScaling currentPowerScaling() { 56 | // Return the current power scaling setting 57 | return _currentPS; 58 | } 59 | 60 | void setSleepMode(Core::SleepMode mode) { 61 | // Read PMCON (Power Mode Control Register) and reset sleep-related fields 62 | uint32_t pmcon = (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) & 0xFFFF00FF; 63 | 64 | // Configure mode 65 | switch (mode) { 66 | case Core::SleepMode::SLEEP0: 67 | case Core::SleepMode::SLEEP1: 68 | case Core::SleepMode::SLEEP2: 69 | case Core::SleepMode::SLEEP3: 70 | pmcon |= (static_cast(mode) - static_cast(Core::SleepMode::SLEEP0)) << PMCON_SLEEP; 71 | break; 72 | 73 | case Core::SleepMode::WAIT: 74 | // SCR.SLEEPDEEP is already set in Core::sleep() 75 | break; 76 | 77 | case Core::SleepMode::RETENTION: 78 | pmcon |= 1 << PMCON_RET; 79 | break; 80 | 81 | case Core::SleepMode::BACKUP: 82 | pmcon |= 1 << PMCON_BKUP; 83 | break; 84 | } 85 | 86 | // Unlock the PMCON register, which is locked by default as a safety mesure 87 | (*(volatile uint32_t*)(BASE + OFFSET_UNLOCK)) 88 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 89 | | OFFSET_PMCON; // ADDR : unlock PMCON 90 | 91 | // Write PMCON 92 | (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) = pmcon; 93 | } 94 | 95 | // Returns the cause of the last backup wake up 96 | BackupWakeUpCause backupWakeUpCause() { 97 | uint32_t bkupwcause = (*(volatile uint32_t*)(BASE + OFFSET_BKUPWCAUSE)); 98 | for (int i = 0; i < 32; i++) { 99 | if (bkupwcause & 1 << i) { 100 | return static_cast(i); 101 | } 102 | } 103 | Error::happened(Error::Module::BPM, ERR_UNKNOWN_BACKUP_WAKEUP_CAUSE, Error::Severity::WARNING); 104 | return BackupWakeUpCause::EIC; // Default value that should not happen 105 | } 106 | 107 | void enableBackupWakeUpSource(BackupWakeUpSource src) { 108 | // BKUPWEN (Backup Wake Up Enable Register) : set the corresponding bit 109 | (*(volatile uint32_t*)(BASE + OFFSET_BKUPWEN)) 110 | |= 1 << static_cast(src); 111 | } 112 | 113 | void disableBackupWakeUpSource(BackupWakeUpSource src) { 114 | // BKUPWEN (Backup Wake Up Enable Register) : clear the corresponding bit 115 | (*(volatile uint32_t*)(BASE + OFFSET_BKUPWEN)) 116 | &= ~(uint32_t)(1 << static_cast(src)); 117 | } 118 | 119 | void disableBackupWakeUpSources() { 120 | // BKUPWEN (Backup Wake Up Enable Register) : clear the register 121 | (*(volatile uint32_t*)(BASE + OFFSET_BKUPWEN)) = 0; 122 | } 123 | 124 | void enableBackupPin(unsigned int eicChannel) { 125 | if (eicChannel < EIC::N_CHANNELS) { 126 | (*(volatile uint32_t*)(BASE + OFFSET_BKUPPMUX)) 127 | |= 1 << static_cast(eicChannel); 128 | } 129 | } 130 | 131 | void disableBackupPin(unsigned int eicChannel) { 132 | if (eicChannel < EIC::N_CHANNELS) { 133 | (*(volatile uint32_t*)(BASE + OFFSET_BKUPPMUX)) 134 | &= ~(uint32_t)(1 << static_cast(eicChannel)); 135 | } 136 | } 137 | 138 | void set32KHzClockSource(CLK32KSource source) { 139 | // Read PMCON (Power Mode Control Register) and reset the CK32S field 140 | uint32_t pmcon = (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) & ~(uint32_t)(1 << PMCON_CK32S); 141 | 142 | // Select the source 143 | if (source == CLK32KSource::RC32K) { 144 | pmcon |= 1 << PMCON_CK32S; 145 | } 146 | 147 | // Unlock the PMCON register, which is locked by default as a safety mesure 148 | (*(volatile uint32_t*)(BASE + OFFSET_UNLOCK)) 149 | = UNLOCK_KEY // KEY : Magic word (see datasheet) 150 | | OFFSET_PMCON; // ADDR : unlock PMCON 151 | 152 | // Write PMCON back 153 | (*(volatile uint32_t*)(BASE + OFFSET_PMCON)) 154 | = pmcon; 155 | } 156 | 157 | void enableInterrupt(void (*handler)(), Interrupt interrupt) { 158 | // Save the user handler 159 | _interruptHandlers[static_cast(interrupt)] = (uint32_t)handler; 160 | 161 | // IER (Interrupt Enable Register) : enable the requested interrupt (PSOK by default) 162 | (*(volatile uint32_t*)(BASE + OFFSET_IER)) 163 | = 1 << _interruptBits[static_cast(interrupt)]; 164 | 165 | // Set the handler and enable the module interrupt at the Core level 166 | Core::setInterruptHandler(Core::Interrupt::BPM, interruptHandlerWrapper); 167 | Core::enableInterrupt(Core::Interrupt::BPM, INTERRUPT_PRIORITY); 168 | } 169 | 170 | void disableInterrupt(Interrupt interrupt) { 171 | // IDR (Interrupt Disable Register) : disable the requested interrupt (PSOK by default) 172 | (*(volatile uint32_t*)(BASE + OFFSET_IDR)) 173 | = 1 << _interruptBits[static_cast(interrupt)]; 174 | 175 | // If no interrupt is enabled anymore, disable the module interrupt at the Core level 176 | if ((*(volatile uint32_t*)(BASE + OFFSET_IMR)) == 0) { 177 | Core::disableInterrupt(Core::Interrupt::BPM); 178 | } 179 | } 180 | 181 | void interruptHandlerWrapper() { 182 | // Call the user handler of every interrupt that is enabled and pending 183 | for (int i = 0; i < N_INTERRUPTS; i++) { 184 | if ((*(volatile uint32_t*)(BASE + OFFSET_IMR)) & (1 << _interruptBits[i]) // Interrupt is enabled 185 | && (*(volatile uint32_t*)(BASE + OFFSET_ISR)) & (1 << _interruptBits[i])) { // Interrupt is pending 186 | void (*handler)() = (void (*)())_interruptHandlers[i]; 187 | if (handler != nullptr) { 188 | handler(); 189 | } 190 | 191 | // Clear the interrupt by reading ISR 192 | (*(volatile uint32_t*)(BASE + OFFSET_ICR)) = 1 << _interruptBits[i]; 193 | } 194 | } 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /libtungsten/sam4l/scif.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCIF_H_ 2 | #define _SCIF_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | 7 | // System Control Interface 8 | // This module manages most of the clock sources : external crystal 9 | // oscillator, DFLL/PLL, low-power default RCSYS oscillator, the faster 10 | // RC80M and RCFAST oscillators, and the Generic Clocks system. 11 | namespace SCIF { 12 | 13 | // Peripheral memory space base address 14 | const uint32_t SCIF_BASE = 0x400E0800; 15 | 16 | // Registers addresses 17 | const uint32_t OFFSET_IER = 0x0000; // Interrupt Enable Register 18 | const uint32_t OFFSET_IDR = 0x0004; // Interrupt Disable Register 19 | const uint32_t OFFSET_IMR = 0x0008; // Interrupt Mask Register 20 | const uint32_t OFFSET_ISR = 0x000C; // Interrupt Status Register 21 | const uint32_t OFFSET_ICR = 0x0010; // Interrupt Clear Register 22 | const uint32_t OFFSET_PCLKSR = 0x0014; // Power and Clocks Status Register 23 | const uint32_t OFFSET_UNLOCK = 0x0018; // Unlock Register 24 | const uint32_t OFFSET_CSCR = 0x001C; // Chip Specific Configuration Register 25 | const uint32_t OFFSET_OSCCTRL0 = 0x0020; // Oscillator Control Register 26 | const uint32_t OFFSET_PLL0 = 0x0024; // PLL0 Control Register 27 | const uint32_t OFFSET_DFLL0CONF = 0x0028; // DFLL0 Config Register 28 | const uint32_t OFFSET_DFLL0VAL = 0x002C; // DFLL Value Register 29 | const uint32_t OFFSET_DFLL0MUL = 0x0030; // DFLL0 Multiplier Register 30 | const uint32_t OFFSET_DFLL0STEP = 0x0034; // DFLL0 Step Register 31 | const uint32_t OFFSET_DFLL0SSG = 0x0038; // DFLL0 Spread Spectrum Generator Control Register 32 | const uint32_t OFFSET_DFLL0RATIO = 0x003C; // DFLL0 Ratio Register 33 | const uint32_t OFFSET_DFLL0SYNC = 0x0040; // DFLL0 Synchronization Register 34 | const uint32_t OFFSET_RCCR = 0x0044; // System RC Oscillator Calibration Register 35 | const uint32_t OFFSET_RCFASTCFG = 0x0048; // 4/8/12MHz RC Oscillator Configuration Register 36 | const uint32_t OFFSET_RCFASTSR = 0x004C; // 4/8/12MHz RC Oscillator Status Register 37 | const uint32_t OFFSET_RC80MCR = 0x0050; // 80MHz RC Oscillator Register 38 | const uint32_t OFFSET_HRPCR = 0x0064; // High Resolution Prescaler Control Register 39 | const uint32_t OFFSET_FPCR = 0x0068; // Fractional Prescaler Control Register 40 | const uint32_t OFFSET_FPMUL = 0x006C; // Fractional Prescaler Multiplier Register 41 | const uint32_t OFFSET_FPDIV = 0x0070; // Fractional Prescaler DIVIDER Register 42 | const uint32_t OFFSET_GCCTRL0 = 0x0074; // Generic Clock Control 0 43 | const uint32_t OFFSET_GCCTRL1 = 0x0078; // Generic Clock Control 1 44 | const uint32_t OFFSET_GCCTRL2 = 0x007C; // Generic Clock Control 2 45 | const uint32_t OFFSET_GCCTRL3 = 0x0080; // Generic Clock Control 3 46 | const uint32_t OFFSET_GCCTRL4 = 0x0084; // Generic Clock Control 4 47 | const uint32_t OFFSET_GCCTRL5 = 0x0088; // Generic Clock Control 5 48 | const uint32_t OFFSET_GCCTRL6 = 0x008C; // Generic Clock Control 6 49 | const uint32_t OFFSET_GCCTRL7 = 0x0090; // Generic Clock Control 7 50 | const uint32_t OFFSET_GCCTRL8 = 0x0094; // Generic Clock Control 8 51 | const uint32_t OFFSET_GCCTRL9 = 0x0098; // Generic Clock Control 9 52 | const uint32_t OFFSET_GCCTRL10 = 0x009C; // Generic Clock Control 10 53 | const uint32_t OFFSET_GCCTRL11 = 0x00A0; // Generic Clock Control 11 54 | 55 | 56 | // Subregisters 57 | const uint32_t PCLKSR_OSC0RDY = 0; 58 | const uint32_t PCLKSR_DFLL0RDY = 3; 59 | const uint32_t PCLKSR_PLL0LOCK = 6; 60 | const uint32_t OSCCTRL0_MODE = 0; 61 | const uint32_t OSCCTRL0_GAIN = 1; 62 | const uint32_t OSCCTRL0_AGC = 3; 63 | const uint32_t OSCCTRL0_STARTUP = 8; 64 | const uint32_t OSCCTRL0_OSCEN = 16; 65 | const uint32_t PLL0_EN = 0; 66 | const uint32_t PLL0_PLLOSC = 1; 67 | const uint32_t PLL0_PLLOPT = 3; 68 | const uint32_t PLL0_PLLDIV = 8; 69 | const uint32_t PLL0_PLLMUL = 16; 70 | const uint32_t PLL0_PLLCOUNT = 24; 71 | const uint32_t DFLL0CONF_EN = 0; 72 | const uint32_t DFLL0CONF_MODE = 1; 73 | const uint32_t DFLL0CONF_RANGE = 16; 74 | const uint32_t DFLL0STEP_FSTEP = 0; 75 | const uint32_t DFLL0STEP_CSTEP = 16; 76 | const uint32_t RCFASTCFG_EN = 0; 77 | const uint32_t RCFASTCFG_TUNEEN = 1; 78 | const uint32_t RCFASTCFG_JITMODE = 2; 79 | const uint32_t RCFASTCFG_NBPERIODS = 4; 80 | const uint32_t RCFASTCFG_FRANGE = 8; 81 | const uint32_t RCFASTCFG_LOCKMARGIN = 12; 82 | const uint32_t RC80MCR_EN = 0; 83 | const uint32_t GCCTRL_CEN = 0; 84 | const uint32_t GCCTRL_DIVEN = 1; 85 | const uint32_t GCCTRL_OSCSEL = 8; 86 | const uint32_t GCCTRL_DIV = 16; 87 | 88 | // Constants 89 | const uint32_t UNLOCK_KEY = 0xAA << 24; 90 | 91 | // Error codes 92 | const uint16_t ERR_PLL_OUT_OF_RANGE = 0x0001; 93 | const uint16_t ERR_DFLL_OUT_OF_RANGE = 0x0002; 94 | 95 | // RCFAST can be configured to operate in any of these frequencies 96 | enum class RCFASTFrequency { 97 | RCFAST_4MHZ = 0b00, 98 | RCFAST_8MHZ = 0b01, 99 | RCFAST_12MHZ = 0b10 100 | }; 101 | 102 | // Each generic clock channel has one or two specific allocations 103 | enum class GCLKChannel { 104 | GCLK0_DFLL, // Also GCLK0 pin 105 | GCLK1_DFLLDITHER, // Also GCLK1 pin 106 | GCLK2_AST, // Also GCLK2 pin 107 | GCLK3_CATB, // Also GCLK3 pin 108 | GCLK4_AES, 109 | GCLK5_GLOC_TC0, 110 | GCLK6_ABDAC_IIS, 111 | GCLK7_USB, 112 | GCLK8_TC1_PEVC0, 113 | GCLK9_PLL0_PEVC1, 114 | GCLK10_ADC, 115 | GCLK11_MASTER 116 | }; 117 | 118 | // Each generic clock can be mapped to any of these clock sources 119 | enum class GCLKSource { 120 | RCSYS = 0, 121 | OSC32K = 1, 122 | DFLL = 2, 123 | OSC0 = 3, 124 | RC80M = 4, 125 | RCFAST = 5, 126 | RC1M = 6, 127 | CLKCPU = 7, 128 | CLKHSB = 8, 129 | CLKPBA = 9, 130 | CLKPBB = 10, 131 | CLKPBC = 11, 132 | CLKPBD = 12, 133 | RC32K = 13, 134 | CLK1K = 15, 135 | PLL = 16, 136 | HRP = 17, 137 | FP = 18, 138 | GCLKIN0 = 19, 139 | GCLKIN1 = 20, 140 | GCLK11 = 21 141 | }; 142 | 143 | enum class PinFunction { 144 | GCLK, 145 | GCLK_IN 146 | }; 147 | 148 | 149 | // Module API 150 | 151 | // RCSYS (115kHz) is the default RC oscillator on which the chip operates after reset 152 | unsigned long getRCSYSFrequency(); 153 | 154 | // RCFAST is a faster RC oscillator than RCSYS, which can operate at 4MHz, 8MHz or 12MHz 155 | void enableRCFAST(RCFASTFrequency frequency); 156 | void disableRCFAST(); 157 | unsigned long getRCFASTFrequency(); 158 | 159 | // OSC0 is an external crystal oscillator, which can operate from 0.6MHz to 30MHz. 160 | // See datasheet §42.7.1 Oscillator 0 (OSC0) Characteristics for more details on 161 | // the required characteristics for this oscillator and its load capacitors. 162 | void enableOSC0(unsigned long frequency); 163 | void disableOSC0(); 164 | unsigned long getOSC0Frequency(); 165 | 166 | // PLL (Phase Locked Loop) is able to generate a high-frequency clock based on a 167 | // lower-frequency one. It is used by the USB module. 168 | void enablePLL(int mul, int div, GCLKSource referenceClock=GCLKSource::RCSYS, unsigned long referenceFrequency=115000UL); 169 | void disablePLL(); 170 | unsigned long getPLLFrequency(); 171 | 172 | // DFLL (Digital Frequency Locked Loop) is similar to the PLL 173 | void enableDFLL(unsigned long frequency, GCLKSource referenceClock=GCLKSource::OSC32K, unsigned long referenceFrequency=32768); 174 | void disableDFLL(); 175 | unsigned long getDFLLFrequency(); 176 | 177 | // RC80M is the faster RC oscillator available, operating at 80MHz. It can power the 178 | // main clock if downscaled to at most 48MHz, or be used as a generic clock. 179 | void enableRC80M(); 180 | void disableRC80M(); 181 | unsigned long getRC810MFrequency(); 182 | 183 | // Generic clocks 184 | void enableGenericClock(GCLKChannel channel, GCLKSource source, bool output=false, uint32_t divider=0); 185 | void disableGenericClock(GCLKChannel channel); 186 | 187 | // Set the pins used for signal lines 188 | void setPin(PinFunction function, int channel, GPIO::Pin pin); 189 | 190 | } 191 | 192 | 193 | #endif -------------------------------------------------------------------------------- /libtungsten/sam4l/i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef _I2C_H_ 2 | #define _I2C_H_ 3 | 4 | #include 5 | #include "gpio.h" 6 | #include "error.h" 7 | 8 | // This module allows the chip to connect to an I2C bus, either in Master or Slave mode. 9 | // I2C is sometimes called TWI (Two-Wire Interface). 10 | // There are 4 distinct I2C controllers : 2 can be either Master or Slave, and 2 can be only Master. 11 | // The peripheral can also operate in SMBus mode (which is a protocol based on I2C), even though this 12 | // is not currently supported by the driver. 13 | // I2C is slower than SPI, but can connect to a larger bus and uses less wires. 14 | namespace I2C { 15 | 16 | // Peripheral memory space base addresses 17 | extern const uint32_t I2C_BASE[]; 18 | 19 | // Register offsets (Master) 20 | const uint32_t OFFSET_M_CR = 0x00; // Control Register 21 | const uint32_t OFFSET_M_CWGR = 0x04; // Clock Waveform Generator Register 22 | const uint32_t OFFSET_M_SMBTR = 0x08; // SMBus Timing Register 23 | const uint32_t OFFSET_M_CMDR = 0x0C; // Command Register 24 | const uint32_t OFFSET_M_NCMDR = 0x10; // Next Command Register 25 | const uint32_t OFFSET_M_RHR = 0x14; // Receive Holding Register 26 | const uint32_t OFFSET_M_THR = 0x18; // Transmit Holding Register 27 | const uint32_t OFFSET_M_SR = 0x1C; // Status Register 28 | const uint32_t OFFSET_M_IER = 0x20; // Interrupt Enable Register 29 | const uint32_t OFFSET_M_IDR = 0x24; // Interrupt Disable Register 30 | const uint32_t OFFSET_M_IMR = 0x28; // Interrupt Mask Register 31 | const uint32_t OFFSET_M_SCR = 0x2C; // Status Clear Register 32 | const uint32_t OFFSET_M_PR = 0x30; // Parameter Register 33 | const uint32_t OFFSET_M_HSCWGR = 0x38; // HS-mode Clock Waveform Generator 34 | const uint32_t OFFSET_M_SRR = 0x3C; // Slew Rate Register 35 | const uint32_t OFFSET_M_HSSRR = 0x40; // HS-mode Slew Rate Register 36 | 37 | // Register offsets (Slave) 38 | const uint32_t OFFSET_S_CR = 0x400; // Control Register 39 | const uint32_t OFFSET_S_NBYTES = 0x404; // NBYTES Register 40 | const uint32_t OFFSET_S_TR = 0x408; // Timing Register 41 | const uint32_t OFFSET_S_RHR = 0x40C; // Receive Holding Register 42 | const uint32_t OFFSET_S_THR = 0x410; // Transmit Holding Register 43 | const uint32_t OFFSET_S_PECR = 0x414; // Packet Error Check Register 44 | const uint32_t OFFSET_S_SR = 0x418; // Status Register 45 | const uint32_t OFFSET_S_IER = 0x41C; // Interrupt Enable Register 46 | const uint32_t OFFSET_S_IDR = 0x420; // Interrupt Disable Register 47 | const uint32_t OFFSET_S_IMR = 0x424; // Interrupt Mask Register 48 | const uint32_t OFFSET_S_SCR = 0x428; // Status Clear Register 49 | const uint32_t OFFSET_S_PR = 0x42C; // Parameter Register 50 | const uint32_t OFFSET_S_HSTR = 0x434; // HS-mode Timing Register 51 | const uint32_t OFFSET_S_SRR = 0x438; // Slew Rate Register 52 | const uint32_t OFFSET_S_HSSRR = 0x43C; // HS-mode Slew Rate Register 53 | 54 | 55 | // Subregisters (Master) 56 | const uint8_t M_CR_MEN = 0; 57 | const uint8_t M_CR_MDIS = 1; 58 | const uint8_t M_CR_SMEN = 4; 59 | const uint8_t M_CR_SMDIS = 5; 60 | const uint8_t M_CR_SWRST = 7; 61 | const uint8_t M_CR_STOP = 8; 62 | const uint8_t M_CWGR_LOW = 0; 63 | const uint8_t M_CWGR_HIGH = 8; 64 | const uint8_t M_CWGR_STASTO = 16; 65 | const uint8_t M_CWGR_DATA = 24; 66 | const uint8_t M_CWGR_EXP = 28; 67 | const uint8_t M_CMDR_READ = 0; 68 | const uint8_t M_CMDR_SADR = 1; 69 | const uint8_t M_CMDR_TENBIT = 11; 70 | const uint8_t M_CMDR_REPSAME = 12; 71 | const uint8_t M_CMDR_START = 13; 72 | const uint8_t M_CMDR_STOP = 14; 73 | const uint8_t M_CMDR_VALID = 15; 74 | const uint8_t M_CMDR_NBYTES = 16; 75 | const uint8_t M_CMDR_PECEN = 24; 76 | const uint8_t M_CMDR_ACKLAST = 25; 77 | const uint8_t M_CMDR_HS = 26; 78 | const uint8_t M_CMDR_HSMCODE = 28; 79 | const uint8_t M_SR_RXRDY = 0; 80 | const uint8_t M_SR_TXRDY = 1; 81 | const uint8_t M_SR_CRDY = 2; 82 | const uint8_t M_SR_CCOMP = 3; 83 | const uint8_t M_SR_IDLE = 4; 84 | const uint8_t M_SR_BUSFREE = 5; 85 | const uint8_t M_SR_ANAK = 8; 86 | const uint8_t M_SR_DNAK = 9; 87 | const uint8_t M_SR_ARBLST = 10; 88 | const uint8_t M_SR_TOUT = 12; 89 | const uint8_t M_SR_PECERR = 13; 90 | const uint8_t M_SR_STOP = 14; 91 | const uint8_t M_SR_MENB = 16; 92 | const uint8_t M_SR_HSMCACK = 17; 93 | const uint8_t M_SRR_DADRIVEL = 0; 94 | const uint8_t M_SRR_DASLEW = 8; 95 | const uint8_t M_SRR_CLDRIVEL = 16; 96 | const uint8_t M_SRR_CLSLEW = 24; 97 | const uint8_t M_SRR_FILTER = 28; 98 | 99 | // Subregisters (Slave) 100 | const uint8_t S_CR_SEN = 0; 101 | const uint8_t S_CR_SMEN = 1; 102 | const uint8_t S_CR_SMATCH = 2; 103 | const uint8_t S_CR_GCMATCH = 3; 104 | const uint8_t S_CR_STREN = 4; 105 | const uint8_t S_CR_SWRST = 7; 106 | const uint8_t S_CR_SMDA = 9; 107 | const uint8_t S_CR_SMHH = 10; 108 | const uint8_t S_CR_PECEN = 11; 109 | const uint8_t S_CR_ACK = 12; 110 | const uint8_t S_CR_CUP = 13; 111 | const uint8_t S_CR_SOAM = 14; 112 | const uint8_t S_CR_SODR = 15; 113 | const uint8_t S_CR_ADR = 16; 114 | const uint8_t S_CR_TENBIT = 26; 115 | const uint8_t S_TR_TLOWS = 0; 116 | const uint8_t S_TR_TTOUT = 8; 117 | const uint8_t S_TR_SUDAT = 16; 118 | const uint8_t S_TR_EXP = 28; 119 | const uint8_t S_SR_RXRDY = 0; 120 | const uint8_t S_SR_TXRDY = 1; 121 | const uint8_t S_SR_SEN = 2; 122 | const uint8_t S_SR_TCOMP = 3; 123 | const uint8_t S_SR_TRA = 5; 124 | const uint8_t S_SR_URUN = 6; 125 | const uint8_t S_SR_ORUN = 7; 126 | const uint8_t S_SR_NAK = 8; 127 | const uint8_t S_SR_SMBTOUT = 12; 128 | const uint8_t S_SR_SMBPECERR = 13; 129 | const uint8_t S_SR_BUSERR = 14; 130 | const uint8_t S_SR_SAM = 16; 131 | const uint8_t S_SR_GCM = 17; 132 | const uint8_t S_SR_SMBHHM = 19; 133 | const uint8_t S_SR_SMBDAM = 20; 134 | const uint8_t S_SR_STO = 21; 135 | const uint8_t S_SR_REP = 22; 136 | const uint8_t S_SR_BTF = 23; 137 | const uint8_t S_SRR_DADRIVEL = 0; 138 | const uint8_t S_SRR_DASLEW = 8; 139 | const uint8_t S_SRR_FILTER = 28; 140 | 141 | // Ports 142 | const int N_PORTS_M = 4; 143 | const int N_PORTS_S = 2; 144 | enum class Port { 145 | I2C0, 146 | I2C1, 147 | I2C2, 148 | I2C3 149 | }; 150 | 151 | enum Dir { 152 | READ, 153 | WRITE 154 | }; 155 | 156 | enum class PinFunction { 157 | SDA, 158 | SCL 159 | }; 160 | 161 | // Timeout for transfer operations 162 | const int TIMEOUT = 1000; // ms 163 | 164 | // Interrupts 165 | const int N_INTERRUPTS = 2; 166 | enum class Interrupt { 167 | ASYNC_READ_FINISHED, 168 | ASYNC_WRITE_FINISHED, 169 | }; 170 | 171 | // Error codes 172 | const Error::Code WARN_PORT_ALREADY_INITIALIZED = 1; 173 | const Error::Code WARN_ARBITRATION_LOST = 2; 174 | const Error::Code ERR_PORT_NOT_INITIALIZED = 3; 175 | const Error::Code ERR_TIMEOUT = 4; 176 | 177 | 178 | // Common functions 179 | void disable(Port port); 180 | uint32_t getStatus(Port port); 181 | void setPin(Port port, PinFunction function, GPIO::Pin pin); 182 | 183 | // Master-mode functions 184 | bool enableMaster(Port port, unsigned int frequency=100000); 185 | int read(Port port, uint8_t address, uint8_t* buffer, int n); 186 | uint8_t read(Port port, uint8_t address); 187 | bool write(Port port, uint8_t address, const uint8_t* buffer, int n); 188 | bool write(Port port, uint8_t address, uint8_t byte); 189 | bool writeRead(Port port, uint8_t address, const uint8_t* txBuffer, int nTX, uint8_t* rxBuffer, int nRX); 190 | bool writeRead(Port port, uint8_t address, uint8_t byte, uint8_t* rxBuffer, int nRX); 191 | bool testAddress(Port port, uint8_t address, Dir direction); 192 | 193 | // Slave-mode functions 194 | bool enableSlave(Port port, uint8_t address); 195 | int read(Port port, uint8_t* buffer, int n, bool async=false); 196 | bool write(Port port, const uint8_t* buffer, int n, bool async=false); 197 | bool isAsyncReadFinished(Port port); 198 | bool isAsyncWriteFinished(Port port); 199 | int getAsyncReadCounter(Port port); 200 | int getAsyncReadBytesSent(Port port); 201 | int getAsyncWriteCounter(Port port); 202 | void enableInterrupt(Port port, void (*handler)(), Interrupt interrupt); 203 | 204 | } 205 | 206 | 207 | #endif --------------------------------------------------------------------------------