├── libraries ├── dos_newlines.sed ├── src │ ├── random │ │ ├── random_from_sernum │ │ ├── random_from_sernum.c │ │ ├── random.c │ │ └── random_from_adc.c │ ├── dma │ │ └── dma.c │ ├── adc │ │ ├── millivolts.c │ │ └── adc.c │ ├── wixel │ │ ├── fixed.s │ │ ├── time.c │ │ ├── delay.s │ │ ├── board.c │ │ └── sleep.c │ ├── uart │ │ └── lib_options.mk │ ├── spi_master │ │ ├── lib_options.mk │ │ └── core │ │ │ └── spi_master.c │ ├── radio_registers │ │ └── radio_registers.c │ ├── usb │ │ └── green_led.c │ ├── gpio │ │ └── gpio.c │ ├── i2c │ │ └── i2c.c │ ├── radio_queue │ │ └── radio_queue.c │ └── radio_com │ │ └── radio_com.c ├── lib │ └── README.txt ├── docs │ ├── wixel_64.png │ ├── docs.html │ └── overviews.dox ├── xpage │ ├── xpage.c │ ├── xpage.rel │ └── xpage.lst ├── include │ ├── wixel.h │ ├── spi.h │ ├── spi1_master.h │ ├── uart1.h │ ├── sleep.h │ ├── dma.h │ ├── random.h │ ├── time.h │ ├── radio_registers.h │ ├── cc2511_types.h │ ├── i2c.h │ ├── radio_queue.h │ ├── com.h │ ├── uart0.h │ ├── radio_com.h │ ├── board.h │ ├── usb_hid_constants.h │ ├── radio_mac.h │ ├── spi0_master.h │ ├── usb_com.h │ ├── adc.h │ ├── radio_link.h │ ├── usb_hid.h │ └── gpio.h └── libs.mk ├── .gitattributes ├── installer ├── wixel_fullname_sm.bmp ├── prepare_sdk.bat ├── sdk.nsi ├── utils.nsi ├── README.txt └── dev_bundle.nsi ├── apps └── dexdrip │ └── options.mk ├── .dir-locals.el ├── make_all.bat ├── .gitignore ├── LICENSE.txt ├── apps.mk ├── radio_registers.h ├── README.md └── Makefile /libraries/dos_newlines.sed: -------------------------------------------------------------------------------- 1 | s/ *$/ /g -------------------------------------------------------------------------------- /libraries/src/random/random_from_sernum: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | libraries/dos_newlines.sed -crlf 2 | -------------------------------------------------------------------------------- /libraries/lib/README.txt: -------------------------------------------------------------------------------- 1 | This is where compiled lib files get put. 2 | -------------------------------------------------------------------------------- /libraries/docs/wixel_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StephenBlackWasAlreadyTaken/wixel-xDrip/HEAD/libraries/docs/wixel_64.png -------------------------------------------------------------------------------- /installer/wixel_fullname_sm.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StephenBlackWasAlreadyTaken/wixel-xDrip/HEAD/installer/wixel_fullname_sm.bmp -------------------------------------------------------------------------------- /apps/dexdrip/options.mk: -------------------------------------------------------------------------------- 1 | APP_LIBS := usb_cdc_acm.lib usb.lib radio_mac.lib radio_queue.lib radio_registers.lib wixel.lib dma.lib uart.lib gpio.lib random.lib adc.lib -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ; This file causes the Emacs text editor to follow our indentation style. 2 | 3 | ( 4 | (c-mode . ((c-basic-offset . 4) (tab-width . 4) (indent-tabs-mode . nil)) ) 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /libraries/xpage/xpage.c: -------------------------------------------------------------------------------- 1 | // Set the _XPAGE symbol so SDCC can properly initialize the XDATA variables 2 | // with initializers. 3 | // sdcc -c xpage.c --model-medium 4 | __sfr __at (0x93) _XPAGE; 5 | -------------------------------------------------------------------------------- /libraries/src/dma/dma.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | DMA14_CONFIG XDATA dmaConfig; 6 | 7 | void dmaInit() 8 | { 9 | DMA1CFG = (uint16)&dmaConfig; 10 | } 11 | -------------------------------------------------------------------------------- /make_all.bat: -------------------------------------------------------------------------------- 1 | :: This Windows batch file will build all of the apps 2 | :: and the libraries that they depend on. 3 | :: You can run it by double-clicking on it. 4 | 5 | @echo off 6 | make 7 | echo You may now close this window. 8 | pause > nul -------------------------------------------------------------------------------- /libraries/include/wixel.h: -------------------------------------------------------------------------------- 1 | // wixel.h includes the header files that most Wixel applications will want to have. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | -------------------------------------------------------------------------------- /installer/prepare_sdk.bat: -------------------------------------------------------------------------------- 1 | :: prepare_wixel_sdk_for_bundle.bat clones the Wixel SDK, 2 | :: and builds the docs so it can be put in to the Wixel 3 | :: Development Bundle. 4 | 5 | cd %~dp0/build 6 | call git clone -o pololu git://github.com/pololu/wixel-sdk.git 7 | cd wixel-sdk 8 | call git config core.autocrlf true 9 | pause 10 | make docs 11 | cd .. -------------------------------------------------------------------------------- /libraries/docs/docs.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | The Wixel SDK Documentation is available in html/index.html. 10 | 11 | -------------------------------------------------------------------------------- /libraries/src/adc/millivolts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "adc.h" 3 | 4 | static uint16 millivoltCalibration = 3300; 5 | 6 | uint16 adcReadVddMillivolts() 7 | { 8 | //return adcRead(15|ADC_REFERENCE_INTERNAL); 9 | return ((uint32)adcRead(15|ADC_REFERENCE_INTERNAL)*3750 + 1023) / 2047; 10 | } 11 | 12 | void adcSetMillivoltCalibration(uint16 vddMillivolts) 13 | { 14 | millivoltCalibration = vddMillivolts; 15 | } 16 | 17 | int16 adcConvertToMillivolts(int16 adcResult) 18 | { 19 | return ((int32)adcResult * millivoltCalibration + 1023) / 2047; 20 | } 21 | -------------------------------------------------------------------------------- /libraries/src/wixel/fixed.s: -------------------------------------------------------------------------------- 1 | ; This file contains the addresses of certain pieces of information that are 2 | ; stored the Wixel's bootloader. 3 | 4 | .module delay 5 | .area CSEG (CODE) 6 | 7 | .globl _serialNumber 8 | .globl _serialNumberStringDescriptor 9 | .globl _bootloaderDeviceDescriptor 10 | 11 | ;; The USB device descriptor of the bootloader is stored at this address: 12 | _bootloaderDeviceDescriptor = 0x03CC 13 | 14 | ;; The four bytes of the serial number are stored in the bootloader at this address: 15 | _serialNumber = 0x03E0 16 | 17 | ;; The Serial Number String Descriptor is stored in the bootloader at this address: 18 | _serialNumberStringDescriptor = 0x03E6 19 | -------------------------------------------------------------------------------- /libraries/src/random/random_from_sernum.c: -------------------------------------------------------------------------------- 1 | /*! \file random_from_sernum.c 2 | * See random.h for more information about this library. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void randomSeedFromSerialNumber(void) 10 | { 11 | // The random number generator only has 16 bits of state, while the 12 | // serial number is 32 bits. No matter what we do here, there will be 13 | // a 1-in-2^16 chance that two Wixels with different serial numbers 14 | // start up with their random number generators in the same state. 15 | // So there is no point in reading all 4 bytes of the serial number. 16 | 17 | randomSeed(serialNumber[0], serialNumber[1]); 18 | } 19 | -------------------------------------------------------------------------------- /libraries/src/uart/lib_options.mk: -------------------------------------------------------------------------------- 1 | # This library will be made by linking uart0.rel and uart1.rel. 2 | LIB_RELS := libraries/src/uart/uart0.rel libraries/src/uart/uart1.rel 3 | 4 | # When those rel (object) files are compiled, there will be a 5 | # special preprocessor flag to specify which UART to use. 6 | libraries/src/uart/uart0.rel : C_FLAGS += -DUART0 7 | libraries/src/uart/uart1.rel : C_FLAGS += -DUART1 8 | 9 | # The rel files will be compiled from uart0.c and uart1.c, 10 | # which will both be copies of core/uart.c. 11 | libraries/src/uart/uart0.c : libraries/src/uart/core/uart.c 12 | $(CP) $< $@ 13 | 14 | libraries/src/uart/uart1.c : libraries/src/uart/core/uart.c 15 | $(CP) $< $@ 16 | 17 | TARGETS += libraries/src/uart/uart0.c libraries/src/uart/uart1.c 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the weird files produces by SDCC during the linking step, for 2 | # example apps/wireless-serial/wireless-serial. To do this, we ignore 3 | # all files inside an app that don't have a period in the name. 4 | apps/*/* 5 | !apps/*/*.* 6 | 7 | # Ignore the files produced by the compiler or makefile as a side 8 | # effect of compilation. 9 | *.adb 10 | *.asm 11 | *.cdb 12 | *.d 13 | *.hex 14 | *.ihx 15 | *.lk 16 | *.lib 17 | *.lnk 18 | *.lst 19 | *.map 20 | *.mem 21 | *.omf 22 | *.rel 23 | *.rst 24 | *.sym 25 | *.wxl 26 | # Ignore eclipse files 27 | .cproject 28 | .project 29 | 30 | # Ignore silly mac files 31 | *.DS_Store 32 | 33 | /docs 34 | 35 | /libraries/src/uart/uart0.c 36 | /libraries/src/uart/uart1.c 37 | /libraries/src/spi_master/spi0_master.c 38 | /libraries/src/spi_master/spi1_master.c 39 | 40 | /installer/build/ -------------------------------------------------------------------------------- /libraries/src/spi_master/lib_options.mk: -------------------------------------------------------------------------------- 1 | # This library will be made by linking spi0_master.rel and spi1_master.rel. 2 | LIB_RELS := libraries/src/spi_master/spi0_master.rel libraries/src/spi_master/spi1_master.rel 3 | 4 | # When those rel (object) files are compiled, there will be a 5 | # special preprocessor flag to specify which SPI to use. 6 | libraries/src/spi_master/spi0_master.rel : C_FLAGS += -DSPI0 7 | libraries/src/spi_master/spi1_master.rel : C_FLAGS += -DSPI1 8 | 9 | # The rel files will be compiled from spi0_master.c and spi1_master.c, 10 | # which will both be copies of core/spi_master.c. 11 | libraries/src/spi_master/spi0_master.c : libraries/src/spi_master/core/spi_master.c 12 | $(CP) $< $@ 13 | 14 | libraries/src/spi_master/spi1_master.c : libraries/src/spi_master/core/spi_master.c 15 | $(CP) $< $@ 16 | 17 | TARGETS += libraries/src/spi_master/spi0_master.c libraries/src/spi_master/spi1_master.c 18 | -------------------------------------------------------------------------------- /libraries/include/spi.h: -------------------------------------------------------------------------------- 1 | /*! \file spi.h 2 | * This file defines constants used in spi0_master.h and spi1_master.h. 3 | */ 4 | 5 | #ifndef _SPI_H 6 | #define _SPI_H 7 | 8 | /*! The SCK line will be low when no data is being transferred. */ 9 | #define SPI_POLARITY_IDLE_LOW 0 10 | /*! The SCK line will be high when no data is being transferred. */ 11 | #define SPI_POLARITY_IDLE_HIGH 1 12 | 13 | /*! Data is sampled/transmitted on the leading edge, when the clock line transitions from idle to active. */ 14 | #define SPI_PHASE_EDGE_LEADING 0 15 | /*! Data is sampled/transmitted on the trailing edge, when the clock like transitions from active to idle. */ 16 | #define SPI_PHASE_EDGE_TRAILING 1 17 | 18 | /*! The most-significant bit is transmitted first. */ 19 | #define SPI_BIT_ORDER_MSB_FIRST 0 20 | 21 | /*! The least-significant bit is transmitted first. */ 22 | #define SPI_BIT_ORDER_LSB_FIRST 1 23 | 24 | 25 | #endif /* SPI_H_ */ 26 | -------------------------------------------------------------------------------- /libraries/include/spi1_master.h: -------------------------------------------------------------------------------- 1 | /*! \file spi1_master.h 2 | * For information about these functions, see spi0_master.h. 3 | * These functions do exactly the same thing as the functions 4 | * in uart0.h, except they apply to USART1 instead of USART0. 5 | */ 6 | 7 | #ifndef _SPI1_MASTER_H 8 | #define _SPI1_MASTER_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | void spi1MasterInit(void); 15 | void spi1MasterSetFrequency(uint32 freq); 16 | void spi1MasterSetClockPolarity(BIT polarity); 17 | void spi1MasterSetClockPhase(BIT phase); 18 | void spi1MasterSetBitOrder(BIT bitOrder); 19 | BIT spi1MasterBusy(void); 20 | uint16 spi1MasterBytesLeft(void); 21 | void spi1MasterTransfer(const uint8 XDATA * txBuffer, uint8 XDATA * rxBuffer, uint16 size); 22 | uint8 spi1MasterSendByte(uint8 XDATA byte); 23 | uint8 spi1MasterReceiveByte(void); 24 | 25 | ISR(URX1, 0); 26 | 27 | #endif /* SPI1_MASTER_H_ */ 28 | -------------------------------------------------------------------------------- /libraries/include/uart1.h: -------------------------------------------------------------------------------- 1 | /** \file uart1.h 2 | * For information about these functions, see uart0.h. 3 | * These functions/variables do exactly the same thing as the functions 4 | * in uart0.h, except they apply to USART1 instead of USART0. 5 | */ 6 | 7 | #ifndef _UART1_H 8 | #define _UART1_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | void uart1Init(); 15 | void uart1SetBaudRate(uint32 baudrate); 16 | void uart1SetParity(uint8 parity); 17 | void uart1SetStopBits(uint8 stopBits); 18 | uint8 uart1TxAvailable(void); 19 | void uart1TxSendByte(uint8 byte); 20 | void uart1TxSend(const uint8 XDATA * buffer, uint8 size); 21 | uint8 uart1RxAvailable(void); 22 | uint8 uart1RxReceiveByte(void); 23 | ISR(UTX1, 0); 24 | ISR(URX1, 0); 25 | extern volatile BIT uart1RxParityErrorOccurred; 26 | extern volatile BIT uart1RxFramingErrorOccurred; 27 | extern volatile BIT uart1RxBufferFullOccurred; 28 | 29 | #endif /* UART_H_ */ 30 | -------------------------------------------------------------------------------- /libraries/src/adc/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | uint16 adcRead(uint8 channel) 6 | { 7 | ADCIF = 0; // Clear the flag. 8 | ADCCON3 = 0b10110000 ^ channel; 9 | while(!ADCIF){}; // Wait for the reading to finish. 10 | 11 | if (ADCH & 0x80) 12 | { 13 | // Despite what the datasheet says, the result was negative. 14 | return 0; 15 | } 16 | else 17 | { 18 | // Note: Despite what the datasheet says, bits 2 and 3 of ADCL are not 19 | // always zero (they seem to be pretty random). We throw them away 20 | // here. 21 | return ADC >> 4; 22 | } 23 | } 24 | 25 | int16 adcReadDifferential(uint8 channel) 26 | { 27 | ADCIF = 0; // Clear the flag. 28 | ADCCON3 = 0b10110000 ^ channel; 29 | while(!ADCIF){}; // Wait for the reading to finish. 30 | 31 | return (int16)ADC >> 4; 32 | } 33 | -------------------------------------------------------------------------------- /libraries/include/sleep.h: -------------------------------------------------------------------------------- 1 | /*! \file sleep.h 2 | * This file provides basic functions for putting the processor to sleep and 3 | * switching oscillators. See the datasheet or design note DN106 for more 4 | * information about the different power modes and their impact. 5 | */ 6 | 7 | #ifndef _WIXEL_SLEEP_H 8 | #define _WIXEL_SLEEP_H 9 | 10 | #include 11 | #include 12 | 13 | ISR(ST, 1); 14 | 15 | /*! Enable sleep timer interrupts and set the timer resolution */ 16 | void sleepInit(void); 17 | 18 | /*! Helper function to switch oscillator to RC OSC from HS XOSC */ 19 | void switchToRCOSC(void); 20 | 21 | /*! Enters sleep mode 1 for x seconds 22 | * This will not disable any other interrupts */ 23 | void sleepMode1(uint16 seconds); 24 | 25 | /*! Enters sleep mode 2 for x seconds 26 | * This will disable all interrupts except the sleep timer 27 | * and restore them after sleeping 28 | */ 29 | void sleepMode2(uint16 seconds); 30 | 31 | /*! Enters sleep mode 3 until an external interrupt occurs 32 | * Note that the sleep timer cannot be used to wake up from PM3 33 | */ 34 | void sleepMode3(); 35 | 36 | #endif -------------------------------------------------------------------------------- /libraries/xpage/xpage.rel: -------------------------------------------------------------------------------- 1 | XH 2 | H 1B areas 2 global symbols 3 | M xpage 4 | O -mmcs51 --model-medium 5 | S __XPAGE Def0093 6 | S .__.ABS. Def0000 7 | A _CODE size 0 flags 0 addr 0 8 | A RSEG size 0 flags 8 addr 0 9 | A RSEG0 size 0 flags 8 addr 0 10 | A RSEG1 size 0 flags 8 addr 0 11 | A REG_BANK_0 size 8 flags 4 addr 0 12 | A DSEG size 0 flags 0 addr 0 13 | A OSEG size 0 flags 4 addr 0 14 | A ISEG size 0 flags 0 addr 0 15 | A IABS size 0 flags 8 addr 0 16 | A BSEG size 0 flags 80 addr 0 17 | A PSEG size 0 flags 50 addr 0 18 | A XSEG size 0 flags 40 addr 0 19 | A XABS size 0 flags 48 addr 0 20 | A XISEG size 0 flags 40 addr 0 21 | A HOME size 0 flags 20 addr 0 22 | A GSINIT0 size 0 flags 20 addr 0 23 | A GSINIT1 size 0 flags 20 addr 0 24 | A GSINIT2 size 0 flags 20 addr 0 25 | A GSINIT3 size 0 flags 20 addr 0 26 | A GSINIT4 size 0 flags 20 addr 0 27 | A GSINIT5 size 0 flags 20 addr 0 28 | A GSINIT size 0 flags 20 addr 0 29 | A GSFINAL size 0 flags 20 addr 0 30 | A CSEG size 0 flags 20 addr 0 31 | A CONST size 0 flags 20 addr 0 32 | A XINIT size 0 flags 20 addr 0 33 | A CABS size 0 flags 28 addr 0 34 | T 00 00 35 | R 00 00 00 02 36 | T 00 00 37 | R 00 00 00 03 38 | T 00 00 39 | R 00 00 00 04 40 | -------------------------------------------------------------------------------- /libraries/src/radio_registers/radio_registers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void radioRegistersInit() 5 | { 6 | 7 | 8 | IOCFG0 =0x0E; 9 | CHANNR =0x00; 10 | FSCTRL1 =0x0A; 11 | FSCTRL0 =0x00; 12 | FREQ2 =0x65; 13 | FREQ1 =0x0A; 14 | FREQ0 =0xAA; 15 | MDMCFG4 =0x4B; 16 | MDMCFG3 =0x11; 17 | MDMCFG2 =0x73; 18 | MDMCFG1 =0x03; 19 | MDMCFG0 =0x55; 20 | DEVIATN =0x00; 21 | MCSM0 =0x14; 22 | FOCCFG =0x0A; 23 | 24 | FSCAL3 =0xA9; 25 | FSCAL2 =0x0A; 26 | FSCAL1 =0x20; 27 | FSCAL0 =0x0D; 28 | 29 | TEST2 =0x81; 30 | TEST1 =0x35; 31 | TEST0 =0x0B; 32 | 33 | PA_TABLE0=0x00; 34 | 35 | SYNC1 =0xD3; 36 | SYNC0 =0x91; 37 | 38 | ADDR =0x00; 39 | 40 | FREND1 =0xB6; 41 | FREND0 =0x10; 42 | 43 | BSCFG =0x6C; 44 | 45 | AGCCTRL2 =0x44; 46 | 47 | AGCCTRL1 =0x00; 48 | //AGCCTRL1 =0x70; 49 | 50 | 51 | AGCCTRL0 =0xB2; 52 | //AGCCTRL0 =0x95; 53 | 54 | PKTCTRL1 =0x04; 55 | PKTCTRL0 =0x05; 56 | 57 | } 58 | 59 | BIT radioCrcPassed() 60 | { 61 | return (LQI & 0x80) ? 1 : 0; 62 | } 63 | 64 | uint8 radioLqi() 65 | { 66 | return LQI & 0x7F; 67 | } 68 | 69 | int8 radioRssi() 70 | { 71 | return ((int8)RSSI)/2 - RSSI_OFFSET; 72 | } 73 | -------------------------------------------------------------------------------- /libraries/src/random/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Returns a new random number. Warning: this is not reentrant. It is possible that this function 6 | * could occasionally return the same random number to an ISR caller as it returns to a main loop 7 | * caller. 8 | */ 9 | uint8 randomNumber() 10 | { 11 | uint8 rand; 12 | while(ADCCON1 & 0x0C); // Wait for the random number to finish. 13 | rand = RNDL; // Get the random number. 14 | ADCCON1 = (ADCCON1 & 0x30) | 0x07; // Start generating the next random number. 15 | return rand; 16 | } 17 | 18 | void randomSeed(uint8 seed_msb, uint8 seed_lsb) 19 | { 20 | // Rescue the random number from these two bad states: 0x0000 and 0x8003. 21 | // Without the code below, the random number generator could get stuck in 22 | // either of these states if it was seeded badly. 23 | if ((seed_lsb == 0 && seed_msb == 0) || (seed_lsb == 0x03 && seed_msb == 0x80)) 24 | { 25 | seed_lsb = 0xAA; 26 | } 27 | 28 | RNDL = seed_msb; 29 | RNDL = seed_lsb; 30 | randomNumber(); 31 | randomNumber(); 32 | randomNumber(); 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2011 Pololu Corporation. For more information, see 2 | 3 | http://www.pololu.com/ 4 | http://forum.pololu.com/ 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /apps.mk: -------------------------------------------------------------------------------- 1 | # This template defines the things we want to add to the makefile for each app. 2 | define APP_template 3 | 4 | APP_RELS := $$(patsubst %.c,%.rel, $$(wildcard apps/$(1)/*.c)) $$(patsubst %.s,%.rel, $$(wildcard apps/$(1)/*.s)) 5 | APP_LIBS := $$(DEFAULT_LIBRARIES) 6 | -include apps/$(1)/options.mk 7 | APP_LIBS := $$(foreach lib, $$(APP_LIBS), libraries/lib/$$(lib)) 8 | 9 | RELs += $$(APP_RELS) 10 | HEXs += apps/$(1)/$(1).hex 11 | 12 | apps/$(1)/$(1).hex : $$(APP_RELS) $$(APP_LIBS) 13 | $$(LINK_COMMAND) 14 | $$(V)mv -f $$(@:%.hex=%.ihx) $$@ 15 | 16 | .PHONY : $(1) 17 | $(1) : apps/$(1)/$(1).wxl 18 | 19 | .PHONY : load_$(1) 20 | load_$(1) : apps/$(1)/$(1).wxl 21 | $$(WIXELCMD) write $$< $$(S) -a 22 | 23 | .PHONY : open_$(1) 24 | open_$(1) : apps/$(1)/$(1).wxl 25 | $$(WIXELCONFIG) $$< 26 | endef 27 | 28 | # Auto detect the apps, and store the list of app names in the APPs variable. 29 | APPs := $(foreach app, $(wildcard apps/*),$(notdir $(app))) 30 | 31 | # Add information about each app to the Makefile. 32 | $(foreach app, $(APPs), $(eval $(call APP_template,$(app)))) 33 | 34 | # Make a phony target called "apps" which builds all the apps. 35 | # You can type "make apps" to build all the apps. 36 | .PHONY : apps 37 | apps: $(APPs) 38 | 39 | -------------------------------------------------------------------------------- /libraries/libs.mk: -------------------------------------------------------------------------------- 1 | DEFAULT_LIBRARIES = radio_com.lib radio_link.lib radio_mac.lib radio_registers.lib \ 2 | random.lib uart.lib usb.lib usb_cdc_acm.lib wixel.lib adc.lib gpio.lib dma.lib 3 | 4 | # This template defines the things we want to add to the makefile for each library. 5 | define LIB_template 6 | 7 | LIB_RELS := $(patsubst %.c,%.rel, $(wildcard libraries/src/$(1)/*.c)) $(patsubst %.s,%.rel, $(wildcard libraries/src/$(1)/*.s)) 8 | -include libraries/src/$(1)/lib_options.mk 9 | 10 | RELs += $$(LIB_RELS) 11 | LIBs += libraries/lib/$(1).lib 12 | 13 | libraries/lib/$(1).lib : $$(LIB_RELS) 14 | 15 | .PHONY : lib_$(1) 16 | lib_$(1) : libraries/lib/$(1).lib 17 | 18 | endef 19 | 20 | # Auto detect the libs, and store the list of app names in the APPs variable. 21 | AUTOLIBs := $(foreach lib, $(wildcard libraries/src/*),$(notdir $(lib))) 22 | 23 | # Add information about each lib to the Makefile. 24 | $(foreach lib, $(AUTOLIBs), $(eval $(call LIB_template,$(lib)))) 25 | 26 | # Make a phony target called "libs" which builds all the libraries. 27 | # You can type "make libs" to build all the libraries. 28 | .PHONY : libs 29 | libs: $(LIBs) 30 | 31 | # You can type "make docs" to build the docs. 32 | .PHONY : docs 33 | docs: 34 | cd libraries && doxygen 35 | cp libraries/docs/docs.html docs/docs.html -------------------------------------------------------------------------------- /libraries/src/random/random_from_adc.c: -------------------------------------------------------------------------------- 1 | /*! \file random_from_adc.c 2 | * See random.h for more information. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | static uint8 adcReadTemp(void) 10 | { 11 | ADCIF = 0; // Clear the flag. 12 | ADCCON3 = 0b10001110; // Read the temperature sensor using VDD as a reference, with only 7 bits of resolution. 13 | while(!ADCIF){}; // Wait for the reading to finish. 14 | return ADCL; 15 | } 16 | 17 | void randomSeedFromAdc(void) 18 | { 19 | randomSeed(adcReadTemp(), adcReadTemp()); 20 | } 21 | 22 | // The function below was commented out because it was not being used and might 23 | // not be needed: 24 | /* Adds another seed to the state of the random number generator. 25 | * If you do this regularly, it will help guarantee that no two Wixels have the 26 | * same random number stream (at least not for long). 27 | */ 28 | /* 29 | void randomRefreshFromAdc() 30 | { 31 | adcReadTemp(); 32 | 33 | while(ADCCON1 & 0x0C); // Wait for the last random number to finish. 34 | RNDL = RNDH ^ ADCL; // Add the seed, but don't throw away the randomness in RNDH. 35 | ADCCON1 = (ADCCON1 & ~0x0C) | 0x07; // Start generating the next random number. 36 | }*/ 37 | 38 | // Local Variables: ** 39 | // mode: C ** 40 | // c-basic-offset: 4 ** 41 | // tab-width: 4 ** 42 | // indent-tabs-mode: nil ** 43 | // end: ** 44 | -------------------------------------------------------------------------------- /libraries/include/dma.h: -------------------------------------------------------------------------------- 1 | /*! \file dma.h 2 | * The dma.lib library provides basic functions and variables for 3 | * the CC2511's DMA controller. 4 | * DMA provides a fast way to copy blocks of data from one memory region or 5 | * peripheral to another. 6 | */ 7 | 8 | #ifndef _DMA_H_ 9 | #define _DMA_H_ 10 | 11 | #include 12 | 13 | /*! Initializes the DMA1CFGL and DMA1CFGH registers to point 14 | * to ::dmaConfig. 15 | * 16 | * This function is called by systemInit(). */ 17 | void dmaInit(void); 18 | 19 | /*! This is the number of the DMA channel we have chosen to use for 20 | * transmitting and receiving radio packets. */ 21 | #define DMA_CHANNEL_RADIO 1 22 | 23 | /*! This struct consists of 4 DMA config registers 24 | * for DMA channels 1-4. */ 25 | typedef struct DMA14_CONFIG 26 | { 27 | /*! This is the DMA configuration struct for DMA channel 1, 28 | * which we have chosen to use for transmitting and receiving 29 | * radio packets. */ 30 | volatile DMA_CONFIG radio; 31 | 32 | /*! Config struct for DMA channel 2 (unassigned) */ 33 | volatile DMA_CONFIG _2; 34 | 35 | /*! Config struct for DMA channel 3 (unassigned) */ 36 | volatile DMA_CONFIG _3; 37 | 38 | /*! Config struct for DMA channel 4 (unassigned) */ 39 | volatile DMA_CONFIG _4; 40 | } DMA14_CONFIG; 41 | 42 | /*! This structure in XDATA holds the configuration options 43 | for DMA channels 1-4. We have to do it this way because the 44 | CC2511's DMA controller expects the configurations of those 45 | channels to be next to each other in memory. The configuration 46 | of channel 0 can be anywhere. You must call dmaInit() 47 | (or systemInit()) for this struct to work. */ 48 | extern DMA14_CONFIG XDATA dmaConfig; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /libraries/src/wixel/time.c: -------------------------------------------------------------------------------- 1 | /* \file time.c 2 | * 3 | * This is the source file for the time component of wixel.lib. 4 | * For information on how to use these functions, see time.h. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | PDATA volatile uint32 timeMs; 12 | 13 | ISR(T4, 0) 14 | { 15 | timeMs++; 16 | // T4CC0 ^= 1; // If we do this, then on average the interrupts will occur precisely 1.000 ms apart. 17 | } 18 | 19 | uint32 getMs() 20 | { 21 | uint8 oldT4IE = T4IE; // store state of timer 4 interrupt (active/inactive?) 22 | uint32 time; 23 | T4IE = 0; // disable timer 4 interrupt 24 | time = timeMs; // copy millisecond timer count into a safe variable 25 | T4IE = oldT4IE; // restore timer 4 interrupt to its original state 26 | return time; // return timer count copy 27 | } 28 | 29 | void timeInit() 30 | { 31 | T4CC0 = 187; 32 | T4IE = 1; // Enable Timer 4 interrupt. (IEN1.T4IE=1) 33 | 34 | // DIV=111: 1:128 prescaler 35 | // START=1: Start the timer 36 | // OVFIM=1: Enable the overflow interrupt. 37 | // MODE=10: Modulo 38 | T4CTL = 0b11111010; 39 | 40 | EA = 1; // Globally enable interrupts (IEN0.EA=1). 41 | } 42 | 43 | void delayMs(uint16 milliseconds) 44 | { 45 | // TODO: make this more accurate. 46 | // A great way would be to use the compare feature of Timer 4 and then 47 | // wait for the right number of compare events to happen, but then we 48 | // can't use that channel for PWM in the future. 49 | while(milliseconds--) 50 | { 51 | delayMicroseconds(250); 52 | delayMicroseconds(250); 53 | delayMicroseconds(250); 54 | delayMicroseconds(249); // there's some overhead, so only delay by 249 here 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /installer/sdk.nsi: -------------------------------------------------------------------------------- 1 | # sdk.nsi - sub-installer script for the Wixel SDK itself 2 | 3 | !define SDK_VER "120127" 4 | 5 | OutFile "build\pololu-wixel-sdk-${SDK_VER}.exe" 6 | 7 | !include LogicLib.nsh 8 | !include FileFunc.nsh 9 | 10 | SetCompressor /solid lzma 11 | RequestExecutionLevel admin 12 | Name "Wixel SDK ${SDK_VER}" 13 | ShowInstDetails show 14 | AllowSkipFiles on 15 | Page directory "" "" checkDirectory 16 | Page instfiles 17 | 18 | !macro TryInstDir path 19 | StrCpy $INSTDIR "${path}" 20 | ${unless} ${FileExists} $INSTDIR 21 | Return 22 | ${endif} 23 | !macroend 24 | 25 | Function .onInit 26 | # Choose an appropriate installation directory that does not already exist. 27 | !insertmacro TryInstDir "C:\wixel-sdk" 28 | !insertmacro TryInstDir "C:\wixel-sdk-${SDK_VER}" 29 | StrCpy $0 "2" 30 | ${do} 31 | !insertmacro TryInstDir "C:\wixel-sdk-${SDK_VER}-$0" 32 | IntOp $0 $0 + 1 33 | ${loop} 34 | FunctionEnd 35 | 36 | Function checkDirectory 37 | # Make sure the user didn't choose a directory that already exists, because that 38 | # could wipe out his previous changes to the SDK and leave him with an 39 | # inconsistent set of SDK files. 40 | ${if} ${FileExists} $INSTDIR 41 | MessageBox MB_OK|MB_ICONSTOP "The folder $INSTDIR already exists. To avoid overwriting previous work, please choose a different folder that does not already exist." 42 | Abort 43 | ${endif} 44 | FunctionEnd 45 | 46 | Section "Main" 47 | SetOutPath $INSTDIR 48 | File /r "build\wixel-sdk" 49 | # TODO: put this note in a better place (e.g. use nsDialogs to put it on its own page) 50 | DetailPrint "PLEASE NOTE: This is NOT the latest version of the Wixel SDK." 51 | DetailPrint "For the latest version with all the latest apps and libraries," 52 | DetailPrint "go to: https://github.com/pololu/wixel-sdk" 53 | SectionEnd -------------------------------------------------------------------------------- /libraries/src/usb/green_led.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // USBFRML is the USB frame number, which is a convenient millisecond 6 | // time base that we can use when we are the configured USB state 7 | // and not in suspend mode. 8 | 9 | BIT usbBlinkActive = 0; 10 | uint8 usbLastActivity; 11 | uint8 usbBlinkStart; 12 | 13 | void usbShowStatusWithGreenLed() 14 | { 15 | if (usbActivityFlag) 16 | { 17 | // Some USB activity happened recently. 18 | usbActivityFlag = 0; 19 | 20 | // Record the time that the USB activity occurred. 21 | usbLastActivity = USBFRML; 22 | 23 | // If we are not already blinking to indicate USB activity, 24 | // start blinking. 25 | if (!usbBlinkActive) 26 | { 27 | usbBlinkActive = 1; 28 | usbBlinkStart = USBFRML; 29 | } 30 | } 31 | 32 | if (usbSuspended() || usbDeviceState == USB_STATE_DETACHED) 33 | { 34 | LED_GREEN(0); // We aren't connected to USB, or we are in suspend 35 | // mode, so turn off the LED. 36 | } 37 | else if (usbDeviceState == USB_STATE_CONFIGURED) 38 | { 39 | if (usbBlinkActive) 40 | { 41 | LED_GREEN((USBFRML - usbBlinkStart) & 64); 42 | 43 | if ((uint8)(USBFRML - usbLastActivity) > 96) 44 | { 45 | usbBlinkActive = 0; 46 | } 47 | } 48 | else 49 | { 50 | LED_GREEN(1); // On solid because we are properly connected. 51 | } 52 | } 53 | else 54 | { 55 | // We do not use USBFRML for timing here because it might not be reliable 56 | // before we reach the configured state. 57 | LED_GREEN(getMs() >> 9 & 1); // Blink with a period of 1024 ms. 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /libraries/include/random.h: -------------------------------------------------------------------------------- 1 | /*! \file random.h 2 | * random.lib is a library that uses the Random Number Generator 3 | * (otherwise known as the Linear Feedback Shift Register (LFSR) or the 4 | * CRC module) 5 | * of the CC251x to generate a pseudo random sequence of numbers. 6 | * 7 | * WARNING: The numbers generated are highly predictable if you know what the 8 | * previous number was. 9 | */ 10 | 11 | #ifndef _RANDOM_H 12 | #define _RANDOM_H 13 | 14 | #include 15 | 16 | /*! Uses two noisy ADC readings (of the internal temperature sensor) to initialize the 17 | * state of the random number generator. 18 | * This function throws away all of the previous state of the random number generator. 19 | * You will generally want to call this function once at the beginning of your program. 20 | * 21 | * Side effects: This function changes ADCL, ADCH, ADCCON3, and ADCIF in order to use the 22 | * extra conversion feature of the ADC. This may make it incompatible with other code that 23 | * uses the ADC. 24 | */ 25 | void randomSeedFromAdc(void); 26 | 27 | /*! Uses the randomly-assigned 4-byte serial number of the Wixel to initialize the 28 | * state of the random number generator. 29 | * This function throws away all of the previous state of the random number generator. 30 | * You will generally want to call this function once at the beginning of your program. 31 | */ 32 | void randomSeedFromSerialNumber(void); 33 | 34 | 35 | /*! \return a random number between 0 and 255. 36 | * Before calling this function, you should call randomSeedFromAdc or 37 | * randomSeedFromSerialNumber to initialize the random number generator. 38 | */ 39 | uint8 randomNumber(void); 40 | 41 | 42 | /* Initializes the random number generator using the specified 16-bit seed. 43 | * \param seed_msb Any number between 0 and 255. 44 | * \param seed_lsb Any number between 0 and 255. 45 | * 46 | * The parameters to this function determine the sequence of random numbers 47 | * produces by the random number generator. 48 | */ 49 | void randomSeed(uint8 seed_msb, uint8 seed_lsb); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /installer/utils.nsi: -------------------------------------------------------------------------------- 1 | # build_tools.nsi - sub-installer script for the pololu GNU build utils 2 | # designed to be run from within a larger installer 3 | 4 | !define UTILS_VER "120126" 5 | 6 | !define STARTDIR ".\build\pololu-gnu-build-utils-${UTILS_VER}" 7 | OutFile ".\build\pololu-gnu-build-utils-${UTILS_VER}.exe" 8 | 9 | !include EnvVarUpdate.nsh 10 | 11 | SetCompressor /solid lzma 12 | RequestExecutionLevel admin 13 | InstallDir "$PROGRAMFILES\Pololu\GNU Build Utilities\" 14 | Name "Pololu GNU Build Utilities ${UTILS_VER}" 15 | ShowInstDetails show 16 | ShowUninstDetails show 17 | AllowSkipFiles on 18 | Page directory 19 | Page instfiles 20 | UninstPage uninstConfirm 21 | UninstPage instfiles 22 | 23 | Section "Main" 24 | SetOutPath "$INSTDIR" 25 | File ${STARTDIR}\*.* 26 | ; File /r "c:\working\kalan\wixel\installer\wixel_tools\pololu_build_utilities_windows\" 27 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\pololu_build_utilities" "DisplayName" "Pololu GNU Build Utilities" 28 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\pololu_build_utilities" "UninstallString" "$\"$INSTDIR\Uninstall Pololu GNU Build Utilities.exe$\"" 29 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\pololu_build_utilities" "Publisher" "Pololu" 30 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\pololu_build_utilities" "DisplayVersion" "${UTILS_VER}" 31 | WriteUninstaller "$INSTDIR\Uninstall Pololu GNU Build Utilities.exe" 32 | ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR" 33 | SectionEnd 34 | 35 | Section "Uninstall" 36 | Delete "$INSTDIR\cat.exe" 37 | Delete "$INSTDIR\cp.exe" 38 | Delete "$INSTDIR\echo.exe" 39 | Delete "$INSTDIR\grep.exe" 40 | Delete "$INSTDIR\LICENSE.txt" 41 | Delete "$INSTDIR\make.exe" 42 | Delete "$INSTDIR\mv.exe" 43 | Delete "$INSTDIR\README.txt" 44 | Delete "$INSTDIR\rm.exe" 45 | Delete "$INSTDIR\sed.exe" 46 | Delete "$INSTDIR\Uninstall Pololu GNU Build Utilities.exe" 47 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\pololu_build_utilities" 48 | ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR" 49 | RMDir "$INSTDIR" 50 | SectionEnd 51 | -------------------------------------------------------------------------------- /libraries/include/time.h: -------------------------------------------------------------------------------- 1 | /*! \file time.h 2 | * This module helps you keep track of time in milliseconds. 3 | * Calling timeInit() sets up a timer (Timer 4) to overflow every millisecond 4 | * (approximately). 5 | * You can read the time at any time by calling getMs(). 6 | * For the interrupt to work, you must write 7 | *
include 
8 | * or 9 | *
include 
10 | * in the source file that contains your main() function. 11 | * Also, you must call boardClockInit() or else the timing will 12 | * be wrong. 13 | * 14 | * Both boardClockInit() and timeInit() are called from systemInit(), so you 15 | * can simply call systemInit() to initialize everything. 16 | */ 17 | 18 | #ifndef _WIXEL_TIME_H 19 | #define _WIXEL_TIME_H 20 | 21 | #include 22 | 23 | /*! Initializes the library. This sets up Timer 4 to tick (approximately) 24 | * every millisecond and enables the Timer 4 interrupt. Note that you 25 | * will also have to call boardClockInit() or systemInit(), to get the system clock running 26 | * at the right speed, otherwise the millisecond timing will be off by a 27 | * large factor. 28 | * 29 | * This function is called by systemInit(). */ 30 | void timeInit(); 31 | 32 | /*! Returns the number of milliseconds that have elapsed since timeInit() 33 | * was called. */ 34 | uint32 getMs(); 35 | 36 | /*! This interrupt fires once per millisecond (approximately) and 37 | * increments timeMs. */ 38 | ISR(T4, 0); 39 | 40 | /*! \param microseconds The number of microseconds delay; any value between 0 and 255. 41 | * 42 | * This function delays for the specified number of microseconds using 43 | * a simple loop. If an interrupt occurs during this function, the delay 44 | * will be longer than specified. */ 45 | void delayMicroseconds(uint8 microseconds); 46 | 47 | /*! \param milliseconds The number of milliseconds delay; any value between 0 and 65535. 48 | * 49 | * This function delays for the specified number of milliseconds using 50 | * a simple loop. If an interrupt occurs during this function, the delay 51 | * will be slightly longer than specified. */ 52 | void delayMs(uint16 milliseconds); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /libraries/src/gpio/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define PIN_SWITCH(operation) switch(pinNumber) { \ 6 | case 0: operation(0,0); break; \ 7 | case 1: operation(0,1); break; \ 8 | case 2: operation(0,2); break; \ 9 | case 3: operation(0,3); break; \ 10 | case 4: operation(0,4); break; \ 11 | case 5: operation(0,5); break; \ 12 | case 10: operation(1,0); break; \ 13 | case 11: operation(1,1); break; \ 14 | case 12: operation(1,2); break; \ 15 | case 13: operation(1,3); break; \ 16 | case 14: operation(1,4); break; \ 17 | case 15: operation(1,5); break; \ 18 | case 16: operation(1,6); break; \ 19 | case 17: operation(1,7); break; \ 20 | case 20: operation(2,0); break; \ 21 | case 21: operation(2,1); break; \ 22 | case 22: operation(2,2); break; \ 23 | case 23: operation(2,3); break; \ 24 | case 24: operation(2,4); break; } 25 | 26 | #define SET_DIGITAL_OUTPUT(port, pin) { \ 27 | P##port##_##pin = value; \ 28 | P##port##DIR |= (1< 12 | 13 | /*! Configures the CC2511's radio module using settings that have 14 | * been tested by Pololu and are known to work. 15 | * 16 | * In summary, these settings are: 17 | * - Data rate = 350 kbps 18 | * - Modulation = MSK 19 | * - Channel 0 frequency = 2403.47 MHz 20 | * - Channel spacing = 286.4 kHz 21 | * - Channel bandwidth = 600 kHz 22 | * 23 | * This function does not configure the PKTLEN, MCSM0, MCSM1, MCSM2, CHANNR, 24 | * or ADDR registers or the DMA: That should be done by higher-level code. 25 | */ 26 | void radioRegistersInit(); 27 | 28 | /*! \return The Link Quality Indicator (LQI) of the last packet received. 29 | * 30 | * According to the CC2511F32 datasheet, the LQI is a metric of the quality of 31 | * the received signal. 32 | * "LQI is best used as a relative measurement of link quality (a high value indicates 33 | * a better link than what a low value does), since the value is dependent on the 34 | * modulation format." */ 35 | uint8 radioLqi(); 36 | 37 | /*! \return The signal strength of the last packet received, if the 38 | * radio just exited RX mode. If the radio is in RX mode, returns a 39 | * continuously-updated estimate of the signal level in the channel. 40 | * The units are dBm. 41 | * 42 | * The RSSI typically be between -100 and -10. 43 | * A higher number (closer to zero if negative) is better. 44 | * RSSI stands for Received Signal Strength Indication. */ 45 | int8 radioRssi(); 46 | 47 | /*! \return 1 if the last packet received has a correct CRC-16, 48 | * 0 otherwise. 49 | * 50 | * If this function returns 0, the data in the last packet received 51 | * was corrupted and should not be relied upon. */ 52 | BIT radioCrcPassed(); 53 | 54 | /*! An offset used by radioRssi() to calculate the RSSI. 55 | * According to Table 68 of the CC2511F32 datasheet, RSSI 56 | * offset for 250kbps is 71. */ 57 | #define RSSI_OFFSET 71 58 | 59 | #endif /* RADIO_REGISTERS_H_ */ 60 | -------------------------------------------------------------------------------- /libraries/src/wixel/delay.s: -------------------------------------------------------------------------------- 1 | .module delay 2 | .optsdcc -mmcs51 --model-medium 3 | .area CSEG (CODE) 4 | 5 | ; void delayMicroseconds(unsigned char microseconds) 6 | ; microseconds: number of microseconds delay; any value between 0 and 255 7 | ; 8 | ; This function delays for the specified number of microseconds using 9 | ; a simple loop. If an interrupt occurs during this function, the delay 10 | ; will be longer than desired. 11 | ; 12 | ; Prerequisites: The chip must be running at 24 MHz, and flash prefetching 13 | ; and caching must be enabled (MEMCTR = 0;). 14 | ; 15 | ; Tests: 16 | ; This function was tested using the following code: 17 | ; P1_0 = 1; 18 | ; delayMicroseconds(100); 19 | ; P1_0 = 0; 20 | ; delayMicroseconds(10); 21 | ; P1_0 = 1; 22 | ; delayMicroseconds(1); 23 | ; P1_0 = 0; 24 | ; The code above produced a high pulse of 100.20/100.16 microseconds, 25 | ; followed by a low pulse of 10.20/10.16 microseconds, 26 | ; followed by a high pulse of 1.20/1.16 microseconds. 27 | ; (The exact length of the pulses depended on the parity of the address 28 | ; of the lcall instruction used to call delayMicroseconds.) 29 | ; 30 | ; Implementation Details: 31 | ; By experimenting, David determined that jumping (e.g. lcall, ret, or 32 | ; ajmp) to an odd address takes one more instruction cycle than jumping 33 | ; to an even address. 34 | ; 35 | ; To get around this, the delayMicroseconds loop contains two jumps: 36 | ; one of these jumps will be to an odd address, and one will be to an 37 | ; even address, so the effects of the object's parity will always 38 | ; cancel out. 39 | ; 40 | ; The ".even" directive doesn't guarantee that the absolute address of 41 | ; a label will be even, it seems to only effect relative positioning 42 | ; within an object file, so we could not use the .even directive. 43 | ; 44 | .globl _delayMicroseconds 45 | loopStart: 46 | nop 47 | nop 48 | nop 49 | nop 50 | ljmp loopJump 51 | nop ; unreachable instruction 52 | nop ; unreachable instruction 53 | nop ; unreachable instruction 54 | nop ; unreachable instruction 55 | loopJump: ; Guaranteed to have a different parity from loopStart. 56 | nop 57 | nop 58 | nop 59 | nop 60 | _delayMicroseconds: 61 | mov a,dpl 62 | jz loopEnd 63 | djnz dpl, loopStart 64 | loopEnd: ret 65 | -------------------------------------------------------------------------------- /radio_registers.h: -------------------------------------------------------------------------------- 1 | /*! \file radio_registers.h 2 | * 3 | * This header file provides a function for configuring the 4 | * radio registers (radioRegistersInit()) and also some small 5 | * functions for reading information from the radio. 6 | */ 7 | 8 | #ifndef _RADIO_REGISTERS_H 9 | #define _RADIO_REGISTERS_H 10 | 11 | #include 12 | 13 | /*! Configures the CC2511's radio module using settings that have 14 | * been tested by Pololu and are known to work. 15 | * 16 | * In summary, these settings are: 17 | * - Data rate = 350 kbps 18 | * - Modulation = MSK 19 | * - Channel 0 frequency = 2403.47 MHz 20 | * - Channel spacing = 286.4 kHz 21 | * - Channel bandwidth = 600 kHz 22 | * 23 | * This function does not configure the PKTLEN, MCSM0, MCSM1, MCSM2, CHANNR, 24 | * or ADDR registers or the DMA: That should be done by higher-level code. 25 | */ 26 | 27 | typedef void (*pFnRadioRegistersInitFunc)(void); 28 | 29 | void setRadioRegistersInitFunc(pFnRadioRegistersInitFunc pFn); 30 | void radioRegistersInit(); 31 | 32 | /*! \return The Link Quality Indicator (LQI) of the last packet received. 33 | * 34 | * According to the CC2511F32 datasheet, the LQI is a metric of the quality of 35 | * the received signal. 36 | * "LQI is best used as a relative measurement of link quality (a high value indicates 37 | * a better link than what a low value does), since the value is dependent on the 38 | * modulation format." */ 39 | uint8 radioLqi(); 40 | 41 | /*! \return The signal strength of the last packet received, if the 42 | * radio just exited RX mode. If the radio is in RX mode, returns a 43 | * continuously-updated estimate of the signal level in the channel. 44 | * The units are dBm. 45 | * 46 | * The RSSI typically be between -100 and -10. 47 | * A higher number (closer to zero if negative) is better. 48 | * RSSI stands for Received Signal Strength Indication. */ 49 | int8 radioRssi(); 50 | 51 | /*! \return 1 if the last packet received has a correct CRC-16, 52 | * 0 otherwise. 53 | * 54 | * If this function returns 0, the data in the last packet received 55 | * was corrupted and should not be relied upon. */ 56 | BIT radioCrcPassed(); 57 | 58 | /*! An offset used by radioRssi() to calculate the RSSI. 59 | * According to Table 68 of the CC2511F32 datasheet, RSSI 60 | * offset for 250kbps is 71. */ 61 | #define RSSI_OFFSET 71 62 | 63 | #endif /* RADIO_REGISTERS_H_ */ 64 | -------------------------------------------------------------------------------- /installer/README.txt: -------------------------------------------------------------------------------- 1 | This directory contains the NSIS source scripts used to compile the 2 | Wixel Development Bundle's installer. For more information, see: 3 | 4 | http://nsis.sourceforge.net 5 | 6 | NSIS is Copyright (C) 1995-2009 Contributors 7 | For full license information, see: 8 | 9 | http://nsis.sourceforge.net/License 10 | 11 | To rebuild the installer from scratch: 12 | 13 | First: 14 | 1. Install NSIS v2.46+, available from http://nsis.sourceforge.net. 15 | You should add the NSIS installation directory to your path so you 16 | can easily run makensis. 17 | 2. Install the "Large strings" build of NSIS on top of that so we 18 | truncate user's paths to 8192 bytes instead of 1024. 19 | 3. Install the EnvVarUpdate plugin for NSIS, available from 20 | http://nsis.sourceforge.net/Environmental_Variables:_append,_prepend,_and_remove_entries 21 | EnvVarUpdate.nsh needs to be put in C:\Program Files (x86)\NSIS\include. 22 | 4. Install Doxygen, available from http://www.stack.nl/~dimitri/doxygen/ 23 | 5. Update BUNDLE_VER and SDK_VER in dev_bundle.nsi to today's date. 24 | 25 | Second, create a new folder named "build" in this directory and assemble the 26 | following in the "build" folder: 27 | 1. A folder named "pololu-gnu-build-utils-VERSION" that contains the 28 | Pololu GNU Build Utilities. Update the UTILS_VER variable in dev_bundle.nsi 29 | and utils.nsi to match this version number if needed. 30 | 2. The SDCC installer, renamed to "sdcc-VERSION-setup.exe". Update the SDCC_VER 31 | variable in dev_bundle.nsi to match this version number if needed. 32 | 3. The Notepad++ installer (e.g. "npp.VERSION.Installer.exe"). Update the 33 | NPP_VER variable in dev_bundle.nsi to match this version number if needed. 34 | 4. The Wixel SDK repository itself, in a folder named "wixel-sdk". 35 | Make sure that wixel-sdk: 36 | - Contains any changes you made in the previous steps. 37 | - Contains a .git folder 38 | - Specifies a remote named pololu in .git/config like this: 39 | [remote "pololu"] 40 | url = git://github.com/pololu/wixel-sdk.git 41 | fetch = +refs/heads/*:refs/remotes/pololu/* 42 | - Has the autocrlf option turned on ("autocrlf = true" in the 43 | [core] section of .git/config) 44 | - Has Doxygen-generated docs in wixel-sdk/docs/html. Run 45 | "make docs" to generate these docs. 46 | - Does NOT have any compilation output files. 47 | You can use prepare_sdk.bat to create the wixel-sdk folder. 48 | 49 | Finally, to create the installer: 50 | 1. Right click on sdk.nsi and select "Compile NSIS Script". 51 | 2. Do the same for utils.nsi. 52 | 3. Do the same for dev_bundle.nsi. 53 | -------------------------------------------------------------------------------- /libraries/include/cc2511_types.h: -------------------------------------------------------------------------------- 1 | /*! \file cc2511_types.h 2 | * This file provides the definitions of useful data types. 3 | */ 4 | 5 | #ifndef _TYPES_H 6 | #define _TYPES_H 7 | 8 | /** An unsigned 8-bit integer. The range of this data type is 0 to 255. **/ 9 | typedef unsigned char uint8; 10 | 11 | /** A signed 8-bit integer. The range of this data type is -128 to 127. **/ 12 | typedef signed char int8; 13 | 14 | /** An unsigned 16-bit integer. The range of this data type is 0 to 65,535. **/ 15 | typedef unsigned short uint16; 16 | 17 | /** A signed 16-bit integer. The range of this data type is -32,768 to 32,767. **/ 18 | typedef signed short int16; 19 | 20 | /** An unsigned 32-bit integer. The range of this data type is 0 to 4,294,967,295. **/ 21 | typedef unsigned long uint32; 22 | 23 | /** A signed 32-bit integer. The range of this data type is -2,147,483,648 to 2,147,483,647. **/ 24 | typedef signed long int32; 25 | 26 | #ifdef SDCC 27 | 28 | /** A 1-bit value that is stored in the processor's bit-addressable memory region. 29 | * The CC2511 has 16 bytes of user-defined bit-addressable memory, so you can have at 30 | * most 128 BIT variables per program. 31 | */ 32 | typedef __bit BIT; 33 | 34 | /** Specifies that the variable is stored in code space (flash memory). 35 | * This is a good choice for variables and data structures that never need to be 36 | * changed. 37 | * See the SDCC docs for more information. 38 | */ 39 | #define CODE __code 40 | 41 | /** Specifies that the variable is stored in the Fast Access Ram section of the chip, 42 | * also known as "Internal Ram". 43 | * This is a good choice for small variables that need to be accessed in many places. 44 | * Reading and writing DATA variables is faster than reading and writing XDATA variables. 45 | * There are only 256 bytes of Fast Access Ram, so use this qualifier sparingly. 46 | * 47 | * Besides being faster, another advantage of DATA over XDATA is the ability to do atomic 48 | * operations. The 8051 instruction set supports several instructions 49 | * (INC, DEC, ORL, ANL, XRL) that let you read, modify, and write a single byte of internal 50 | * RAM with one instruction. 51 | */ 52 | #define DATA __data 53 | 54 | /** Specifies that the variable is stored in the paged data area (the first 256 bytes 55 | * of XDATA). This is the default memory space for variables. Accessing PDATA variables 56 | * takes less code space than accessing XDATA variables. 57 | */ 58 | #define PDATA __pdata 59 | 60 | /** Specifies that the variable is stored in the Slow Access Ram section of the chip, 61 | * also known as "External Ram". 62 | * This is a good choice for large buffers or variables that don't need to be accessed 63 | * quickly. The CC2511 has 3840 bytes of Slow Access Ram. 64 | */ 65 | #define XDATA __xdata 66 | 67 | #elif defined(__CDT_PARSER__) 68 | 69 | // Avoid syntax and semantic errors in eclipse. 70 | #define CODE 71 | #define XDATA 72 | #define DATA 73 | #define PDATA 74 | typedef unsigned char BIT; 75 | #define ISR(source, bank) void ISR_##source() 76 | #define __reentrant 77 | 78 | #else 79 | #error "Unknown compiler." 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /installer/dev_bundle.nsi: -------------------------------------------------------------------------------- 1 | # wixel_tools_mui.nsi - installer script for the wixel development bundle 2 | 3 | !define BUNDLE_VER "120127" 4 | !define SDK_VER "120127" 5 | !define SDCC_VER "3.1.0" 6 | !define UTILS_VER "120126" 7 | !define NPP_VER "5.9.8" 8 | 9 | !define STARTDIR ".\build" 10 | OutFile ".\build\wixel-dev-bundle-${BUNDLE_VER}.exe" 11 | 12 | !include FileFunc.nsh 13 | !include EnvVarUpdate.nsh 14 | !include MUI.nsh 15 | 16 | SetCompressor /solid lzma 17 | RequestExecutionLevel admin 18 | 19 | ; !define STARTDIR=c:\foo\bar 20 | !define MUI_HEADERIMAGE 21 | !define MUI_HEADERIMAGE_BITMAP_NOSTRETCH 22 | !define MUI_HEADERIMAGE_BITMAP ".\wixel_fullname_sm.bmp" 23 | !define MUI_FINISHPAGE_NOAUTOCLOSE 24 | 25 | !define MUI_COMPONENTSPAGE_SMALLDESC 26 | 27 | !insertmacro MUI_PAGE_COMPONENTS 28 | !insertmacro MUI_PAGE_INSTFILES 29 | 30 | Name "Pololu Wixel Development Bundle" 31 | !insertmacro MUI_LANGUAGE "English" 32 | 33 | LangString DESC_SDK ${LANG_ENGLISH} "Libraries and example code for the Wixel." 34 | LangString DESC_SDCC ${LANG_ENGLISH} "Free C compiler that is used to compile the code in the Wixel SDK." 35 | LangString DESC_UTILS ${LANG_ENGLISH} "Open-source utilities required by the Wixel SDK: cat, cp, echo, grep, make, mv, rm, and sed." 36 | LangString DESC_NPP ${LANG_ENGLISH} "Free source code editor which is nice to use when editing Wixel code." 37 | 38 | Section "Wixel SDK ${SDK_VER}" SDK 39 | DetailPrint "Installing wixel-sdk..." 40 | SetOutPath "$TEMP" 41 | File "${STARTDIR}\pololu-wixel-sdk-${SDK_VER}.exe" 42 | ExecWait "$TEMP\pololu-wixel-sdk-${SDK_VER}.exe" 43 | SectionEnd 44 | 45 | Section "Pololu GNU Build Utilities ${UTILS_VER}" UTILS 46 | DetailPrint "Installing Pololu GNU Build Utilities..." 47 | SetOutPath "$TEMP" 48 | File "${STARTDIR}\pololu-gnu-build-utils-${UTILS_VER}.exe" 49 | #MessageBox MB_OK "The Wixel Dev Bundle will now launch the installer for the Pololu GNU Build Utilities" 50 | ExecWait "$TEMP\pololu-gnu-build-utils-${UTILS_VER}.exe" 51 | SectionEnd 52 | 53 | Section "SDCC ${SDCC_VER}" SDCC 54 | DetailPrint "Installing SDCC..." 55 | SetOutPath "$TEMP" 56 | File "${STARTDIR}\sdcc-${SDCC_VER}-setup.exe" 57 | #MessageBox MB_OK "The Wixel Development Bundle will now launch the installer for SDCC ${SDCC_VER}." 58 | ExecWait "$TEMP\sdcc-${SDCC_VER}-setup.exe" 59 | DetailPrint "Making sure that SDCC's path is set properly..." 60 | ReadRegStr $9 HKLM "Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\SDCC" 'InstallLocation' 61 | ReadRegStr $9 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SDCC" 'InstallLocation' 62 | ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$9\bin" 63 | SectionEnd 64 | 65 | Section "Notepad++ v${NPP_VER}" NPP 66 | SetOutPath "$TEMP" 67 | DetailPrint "Installing Notepad++..." 68 | File "${STARTDIR}\npp.${NPP_VER}.Installer.exe" 69 | #MessageBox MB_OK "The Wixel Development Bundle will now launch the installer for Notepad++." 70 | ExecWait "$TEMP\npp.${NPP_VER}.Installer.exe" 71 | SectionEnd 72 | 73 | !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN 74 | !insertmacro MUI_DESCRIPTION_TEXT ${SDK} $(DESC_SDK) 75 | !insertmacro MUI_DESCRIPTION_TEXT ${SDCC} $(DESC_SDCC) 76 | !insertmacro MUI_DESCRIPTION_TEXT ${UTILS} $(DESC_UTILS) 77 | !insertmacro MUI_DESCRIPTION_TEXT ${NPP} $(DESC_NPP) 78 | !insertmacro MUI_FUNCTION_DESCRIPTION_END -------------------------------------------------------------------------------- /libraries/include/i2c.h: -------------------------------------------------------------------------------- 1 | /*! \file i2c.h 2 | * The i2c.lib library provides a basic software (bit-banging) 3 | * implementation of a master node for I2C communication (the CC2511 4 | * does not have a hardware I2C module). This library does not 5 | * support multi-master I2C buses. 6 | * 7 | * By default, the SCL pin is assigned to P1_0, the SDA pin is 8 | * assigned to P1_1, and the bus frequency is 100 kHz with a 10 ms timeout. 9 | */ 10 | 11 | #ifndef _I2C_H 12 | #define _I2C_H 13 | 14 | #include 15 | 16 | /*! Number of the pin to use as the SCL (clock) line of the I2C bus. 17 | * See the gpio.h documentation for pin number values. 18 | */ 19 | extern uint8 DATA i2cPinScl; 20 | 21 | /*! Number of the pin to use as the SDA (data) line of the I2C bus. 22 | * See the gpio.h documentation for pin number values. 23 | */ 24 | extern uint8 DATA i2cPinSda; 25 | 26 | /*! This bit is a flag that is set whenever a timeout occurs on the 27 | * I2C bus waiting for the SCL line to go high. The flag must be 28 | * manually cleared after being read. The i2cSetTimeout() function can be used 29 | * to specify the timeout delay. 30 | */ 31 | extern BIT i2cTimeoutOccurred; 32 | 33 | /*! Sets the I2C bus clock frequency. This implementation limits the 34 | * range of possible frequencies to 2-500 kHz; because of rounding inaccuracies and timing constraints, the actual frequency might be lower than 35 | * the selected frequency, but it is guaranteed never to be higher. The default 36 | * frequency is 100 kHz. Common I2C speeds are 10 kHz (low speed), 37 | * 100 kHz (standard), and 400 kHz (high speed). 38 | * 39 | * \param freqKHz Frequency in kHz. 40 | */ 41 | void i2cSetFrequency(uint16 freqKHz); 42 | 43 | /*! Sets the allowed delay before a low SCL line causes an I2C bus 44 | * timeout, which aborts the I2C transaction and sets the 45 | * #i2cTimeoutOccurred flag. The default timeout is 10 ms. 46 | * 47 | * \param timeoutMs Timeout in milliseconds. 48 | */ 49 | void i2cSetTimeout(uint16 timeoutMs); 50 | 51 | /*! Generates an I2C START condition. 52 | */ 53 | void i2cStart(void); 54 | 55 | /*! Generates an I2C STOP condition. 56 | */ 57 | void i2cStop(void); 58 | 59 | /*! Writes a byte to the I2C bus (performs a master transmit). 60 | * 61 | * \param byte The byte to be transmitted. 62 | * 63 | * \return 0 if an ACK is received from the slave device, 1 if a NACK is 64 | * received. This return value is not meaningful if a timeout occurs 65 | * during the write transaction (indicated by the #i2cTimeoutOccurred 66 | * flag). 67 | */ 68 | BIT i2cWriteByte(uint8 byte); 69 | 70 | /*! Reads a byte from the I2C bus (performs a master receive). 71 | * 72 | * \param nack If 1, a NACK will be sent to the slave device instead of an 73 | * ACK after this byte is received. (This is used to signal 74 | * conclusion of a transfer from the slave to the master.) 75 | * 76 | * \return The byte received from the slave device. This return value is not 77 | * meaningful if a timeout occurs during the read transaction 78 | * (indicated by the #i2cTimeoutOccurred flag). 79 | */ 80 | uint8 i2cReadByte(BIT nack); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /libraries/include/radio_queue.h: -------------------------------------------------------------------------------- 1 | /*! \file radio_queue.h 2 | * radio_queue.lib is a library that provides a simple mechanism 3 | * for queuing the transmission and reception of RF packets on a device. It 4 | * does not ensure reliability, nor does it specify a format for the packet 5 | * contents, other than requiring the first byte of the packet to contain its 6 | * length. This library depends on radio_mac.lib. 7 | */ 8 | 9 | #ifndef _RADIO_QUEUE 10 | #define _RADIO_QUEUE 11 | 12 | #include 13 | #include 14 | 15 | /*! Each packet can contain at most 19 bytes of payload. (This was chosen to 16 | * match radio_link's 18-byte payload + 1-byte header.) */ 17 | #define RADIO_QUEUE_PAYLOAD_SIZE 19 18 | 19 | /*! Defines the frequency to use. Valid values are from 20 | * 0 to 255. To avoid interference, the channel numbers of 21 | * different Wixel pairs operating in the should be at least 22 | * 2 apart. (This is a Wixel App parameter; the user can set 23 | * it using the Wixel Configuration Utility.) 24 | */ 25 | extern int32 CODE param_radio_channel; 26 | 27 | /*! If this variable is set to 1, received packets will be added to the RX queue 28 | * even if they have CRC errors. This means that you will get corrupt and 29 | * spurious data in addition to good data, but it can be useful for applications 30 | * such as an RF packet sniffer. This variable has a value of 0 by default. 31 | */ 32 | extern BIT radioQueueAllowCrcErrors; 33 | 34 | /*! Initializes the radio_queue library and the lower-level 35 | * libraries that radio_queue depends on. This must be called before 36 | * any other functions in the library. */ 37 | void radioQueueInit(void); 38 | 39 | /*! \return The number of radio packet buffers that are currently free 40 | * (available to hold data). 41 | * 42 | * This function has no side effects. */ 43 | uint8 radioQueueTxAvailable(void); 44 | 45 | /*! \return The number of radio packet buffers that are currently busy 46 | * (holding a data packet that has not been successfully sent yet). 47 | * 48 | * This function has no side effects. */ 49 | uint8 radioQueueTxQueued(void); 50 | 51 | /*! Returns a pointer to the current packet, or 0 if no packet is available. 52 | * This function has no side effects. To populate this packet, you should 53 | * write the length of the payload data (which must not exceed 54 | * RADIO_QUEUE_PAYLOAD_SIZE) to offset 0, and write the data starting at 55 | * offset 1. After you have put this data in the packet, call 56 | * radioQueueTxSendPacket() to actually queue the packet up to be sent on 57 | * the radio. 58 | * Example usage: 59 | *
60 |  *   uint8 XDATA * packet = radioQueueTxCurrentPacket();
61 |  *   if (packet != 0)
62 |  *   {
63 |  *       packet[0] = 3;   // must not exceed RADIO_QUEUE_PAYLOAD_SIZE
64 |  *       packet[1] = 'a';
65 |  *       packet[2] = 'b';
66 |  *       packet[3] = 'c';
67 |  *       radioQueueTxSendPacket();
68 |  *   }
69 |  * 
70 | */ 71 | uint8 XDATA * radioQueueTxCurrentPacket(void); 72 | 73 | /*! Sends the current TX packet. See the documentation of 74 | * radioQueueTxCurrentPacket() for details. 75 | */ 76 | void radioQueueTxSendPacket(void); 77 | 78 | /*! Returns a pointer to the current RX packet (the earliest packet received 79 | * by radio_queue which has not been processed yet by higher-level code). 80 | * Returns 0 if there is no RX packet available. 81 | * The RX packet has the same format as the TX packet: the length of the 82 | * payload is at offset 0 and the data starts at offset 1. When you are 83 | * done reading the packet, you should call radioQueueRxDoneWithPacket(). 84 | * This frees the current packet buffer so it can receive another packet. 85 | */ 86 | uint8 XDATA * radioQueueRxCurrentPacket(void); // returns 0 if no packet is available. 87 | 88 | /*! Frees the current RX packet so that you can advance to processing 89 | * the next one. See the radioQueueRxCurrentPacket() documentation for details. */ 90 | void radioQueueRxDoneWithPacket(void); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /libraries/include/com.h: -------------------------------------------------------------------------------- 1 | /*! \file com.h 2 | * Contains common code that is needed by usb_com.h, uart1.h, and uart0.h. 3 | * 4 | * The ACM_SERIAL_STATE_* defines all come from Table 31 of PSTN specification. 5 | * They serve to define the bits used in 6 | * usbComTxSignals() (see usb_com.h). 7 | * 8 | * The ACM_CONTROL_LINE_* defines all from the Table 18 of the PSTN specification. 9 | * They serve to define the bits returned by usbComRxSignals() (see usb_com.h). 10 | * 11 | * PSTN is a subclass of the USB CDC Device Class. You can find the specification 12 | * of PSTN in PSTN120.pdf, available for download from USB Implementers Forum at 13 | * this url: http://www.usb.org/developers/devclass_docs 14 | * 15 | */ 16 | 17 | #ifndef _COM_H 18 | #define _COM_H 19 | 20 | /** UART State Bit Values from PSTN 1.20 Table 31. ****************************/ 21 | 22 | /*! State of receiver carrier detection mechanism of device. 23 | * Also known as CD or CdHolding. */ 24 | #define ACM_SERIAL_STATE_RX_CARRIER (1<<0) 25 | 26 | /*! State of transmission carrier. Also known as DSR or DsrHolding. */ 27 | #define ACM_SERIAL_STATE_TX_CARRIER (1<<1) 28 | 29 | /*! State of break detection mechanism of the device. */ 30 | #define ACM_SERIAL_STATE_BREAK (1<<2) 31 | 32 | /*! State of ring signal detection of the device. */ 33 | #define ACM_SERIAL_STATE_RING_SIGNAL (1<<3) 34 | 35 | /*! A framing error has occurred. */ 36 | #define ACM_SERIAL_STATE_FRAMING (1<<4) 37 | 38 | /*! A parity error has occurred. */ 39 | #define ACM_SERIAL_STATE_PARITY (1<<5) 40 | 41 | /*! Received data has been discarded due to overrun in the device. */ 42 | #define ACM_SERIAL_STATE_OVERRUN (1<<6) 43 | 44 | /*! These are the "irregular" signals, described in PSTN 1.20 Section 6.5.4. 45 | * These bits represent events that can be reported to the USB host. 46 | * They are more like interrupts than I/O lines. 47 | * See the usbComTxControlSignals() function in usb_com.h for more information. */ 48 | #define ACM_IRREGULAR_SIGNAL_MASK (ACM_SERIAL_STATE_BREAK | ACM_SERIAL_STATE_RING_SIGNAL | ACM_SERIAL_STATE_FRAMING | ACM_SERIAL_STATE_PARITY | ACM_SERIAL_STATE_OVERRUN) 49 | 50 | /*! Indicates to the CDE if DTE is present or not. 51 | * - 0 = Not Present 52 | * - 1 = Present 53 | * */ 54 | #define ACM_CONTROL_LINE_DTR 1 55 | 56 | /*! Carrier control for half duplex modems. 57 | * - 0 = Deactivate carrier. 58 | * - 1 = Activate carrier. */ 59 | #define ACM_CONTROL_LINE_RTS 2 60 | 61 | /*! Specifies the type of coding to use on an asynchronous serial line. 62 | * 63 | * This struct is defined in PSTN120.pdf in Table 17: Line Coding Structure. 64 | * PSTN120.pdf is available for download from USB Implementers Forum at 65 | * this url: http://www.usb.org/developers/devclass_docs */ 66 | typedef struct ACM_LINE_CODING 67 | { 68 | /*! Baud rate, in bits per second. */ 69 | unsigned long dwDTERate; 70 | 71 | /*! The number of stop bits. Valid values are #STOP_BITS_1, 72 | * #STOP_BITS_1_5, and #STOP_BITS_2. */ 73 | unsigned char bCharFormat; 74 | 75 | /*! The parity type. Valid values are #PARITY_NONE, #PARITY_ODD, 76 | * #PARITY_EVEN, #PARITY_MARK, and #PARITY_SPACE.*/ 77 | unsigned char bParityType; 78 | 79 | /*! The number of data bits in each byte. Valid values 80 | * are 5, 6, 7, 8 and 16. */ 81 | unsigned char bDataBits; 82 | } ACM_LINE_CODING; 83 | 84 | /*! No parity. Each serial byte will only have 8 bits. */ 85 | #define PARITY_NONE 0 86 | 87 | /*! Odd parity. The total number of data bits that are 1 will be odd. */ 88 | #define PARITY_ODD 1 89 | 90 | /*! Even parity. The total number of data bits that are 1 will be even. */ 91 | #define PARITY_EVEN 2 92 | 93 | /*! Mark parity. Ninth bit of each byte will be logical 1. */ 94 | #define PARITY_MARK 3 95 | 96 | /*! Mark parity. Ninth bit of each byte will be logical 0. */ 97 | #define PARITY_SPACE 4 98 | 99 | /*! The end of each byte will have 1 stop bit. */ 100 | #define STOP_BITS_1 0 101 | 102 | /*! The end of each serial byte will have 1.5 stop bits. 103 | * The CC2511's UARTs do not actually support this option. */ 104 | #define STOP_BITS_1_5 1 105 | 106 | /*! The end of each serial byte will have 2 stop bits. 107 | * The CC2511's UARTs do not support this option very well; 108 | * the UART library may fail to detect framing errors 109 | * from the second stop bit when this option is used. 110 | * */ 111 | #define STOP_BITS_2 2 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /libraries/include/uart0.h: -------------------------------------------------------------------------------- 1 | /*! \file uart0.h 2 | * The uart.lib library allows you to send and receive a stream 3 | * of asynchronous serial bytes on USART0 and/or USART1 in UART mode. 4 | * This library uses circular buffers and interrupts for both RX and TX 5 | * so it is capable of sending 6 | * and receiving a continuous stream of bytes with no gaps. 7 | * 8 | * To use this library, you must include uart0.h or uart1.h in your app: 9 | \code 10 | #include // for UART 0 11 | #include // for UART 1 12 | \endcode 13 | * 14 | * Since this library uses interrupts, the include statement must be present 15 | * in the file that contains main(). 16 | * 17 | * The API for using UART 1 is the same as the API for using UART 0 that is 18 | * documented here, except all the function and variable names begin with 19 | * "uart1" instead of "uart0". 20 | * 21 | * For UART0, this library uses Alternative Location 1: P0_3 is TX, P0_2 is RX. 22 | * For UART1, this library uses Alternative Location 2: P1_6 is TX, P1_7 is RX. 23 | * This library does not yet allow you to choose which UART location to use. 24 | */ 25 | 26 | #ifndef _UART0_H 27 | #define _UART0_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | /*! Initializes the library. 34 | * 35 | * This must be called before any of other functions with names that 36 | * begin with "uart0". */ 37 | void uart0Init(); 38 | 39 | /*! Sets the baud rate. 40 | * 41 | * \param baudrate The baud rate, in bits per second (bps). Must be between 23 and 1,500,000. */ 42 | void uart0SetBaudRate(uint32 baudrate); 43 | 44 | /*! Sets the parity type of the serial port. 45 | * 46 | * \param parity Should be either #PARITY_NONE, #PARITY_ODD, #PARITY_EVEN, #PARITY_MARK, 47 | * or #PARITY_SPACE. 48 | * 49 | * The default is #PARITY_NONE. 50 | */ 51 | void uart0SetParity(uint8 parity); 52 | 53 | /*! Sets the number of stop bits to be transmitted and checked for during reception. 54 | * 55 | * \param stopBits Should be either #STOP_BITS_1 or #STOP_BITS_2. 56 | * 57 | * The CC2511's UARTs do not actually support 1.5 stop bits, so if the argument to 58 | * this function is #STOP_BITS_1_5, the UART will be set to 1 stop bit instead. 59 | * 60 | * The CC2511's UARTs do not support having 2 stop bits very well, because the 61 | * the framing error bit (UxCSR.FE) is set 1 bit duration after the interrupt 62 | * is triggered. Therefore, if stopBits is #STOP_BITS_2, this library may fail to 63 | * detect framing errors from the second stop bit. Also, the next byte received 64 | * after the framing error occurred may be thrown out even if that byte is valid. 65 | * 66 | * The default is #STOP_BITS_1. 67 | */ 68 | void uart0SetStopBits(uint8 stopBits); 69 | 70 | /*! \return The number of bytes available in the TX buffer. 71 | */ 72 | uint8 uart0TxAvailable(void); 73 | 74 | /*! Adds a byte to the TX buffer, which means it will be sent on UART0's TX line later. 75 | * \param byte The byte to send. 76 | * 77 | * This is a non-blocking function: you must call uart0TxAvailable() before calling this 78 | * function and be sure not to add too many bytes to the buffer. The number of times you call 79 | * this should not exceed the last value returned by uart0TxAvailable(). 80 | */ 81 | void uart0TxSendByte(uint8 byte); 82 | 83 | /*! Adds bytes to the TX buffer, which means they will be sent on UART0's TX 84 | * line later. This is a non-blocking function: you must call uart0TxAvailable() 85 | * before calling this function be sure not to add too many bytes to the buffer. 86 | * The \p size param should not exceed the last value returned by uart0TxAvailable(). 87 | * 88 | * \param buffer A pointer to the bytes to send. 89 | * \param size The number of bytes to send. 90 | */ 91 | void uart0TxSend(const uint8 XDATA * buffer, uint8 size); 92 | 93 | /*! \return The number of bytes in the RX buffer. 94 | * 95 | * You can use this function to see if any bytes have been received, and 96 | * then use uart0RxReceiveByte() to actually get the byte and process it. 97 | */ 98 | uint8 uart0RxAvailable(void); 99 | 100 | /*! \return A byte from the RX buffer. 101 | * 102 | * This is a non-blocking function: you must call uart0RxAvailable() before calling 103 | * this function and be sure not to read too many bytes. The number 104 | * of times you call this should not exceed the last value returned by 105 | * uart0RxAvailable(). 106 | * 107 | * Bytes are returned in the order they were received on the RX line. 108 | * 109 | */ 110 | uint8 uart0RxReceiveByte(void); 111 | 112 | /*! Transmit interrupt. */ 113 | ISR(UTX0, 0); 114 | 115 | /*! Receive interrupt. */ 116 | ISR(URX0, 0); 117 | 118 | /*! The library sets this to 1 whenever a parity error occurs. */ 119 | extern volatile BIT uart0RxParityErrorOccurred; 120 | 121 | /*! The library sets this to 1 whenever a framing error occurs. */ 122 | extern volatile BIT uart0RxFramingErrorOccurred; 123 | 124 | /*! The library sets this to 1 whenever a new byte arrives and 125 | * the RX buffer is full. 126 | * In that case, the byte will be discarded.*/ 127 | extern volatile BIT uart0RxBufferFullOccurred; 128 | 129 | #endif /* UART_H_ */ 130 | -------------------------------------------------------------------------------- /libraries/include/radio_com.h: -------------------------------------------------------------------------------- 1 | /*! \file radio_com.h 2 | * The radio_com.lib library provides reliable, ordered 3 | * delivery and reception of a stream of bytes between two devices. 4 | * This library depends on radio_link.lib. 5 | * For many applications, this library is easier to use than 6 | * radio_link.lib because this library takes care of 7 | * dividing the stream of bytes into packets. 8 | * 9 | * This library depends on radio_link.lib, which depends on 10 | * radio_mac.lib, which uses an interrupt. 11 | * For this library to work, you must write 12 | * include 13 | * in the source file that contains your main() function. 14 | * 15 | * This library has the same limitations as radio_link.lib: 16 | * It does not work if there are more than two Wixels broadcasting 17 | * on the same channel. 18 | * For wireless communication between more than two Wixels, you can use 19 | * radio_queue.lib (see radio_queue.h). 20 | * 21 | * This library also supports sending 8 control signals to the other Wixel 22 | * and receiving 8 control signals from the other Wixel. 23 | */ 24 | 25 | #ifndef _RADIO_COM_H_ 26 | #define _RADIO_COM_H_ 27 | 28 | #include 29 | 30 | /*! Initializes the radio_com.lib library and the 31 | * lower-level libraries that it depends on. 32 | * This must be called before any of the other radioCom* functions. */ 33 | void radioComInit(void); 34 | 35 | /*! This is a configuration option for the radio_com.lib library that 36 | * can be set by higher-level code. 37 | * The default value is 0. 38 | * 39 | * When this bit is 1, the radio_com library guarantees that the higher-level code 40 | * receives notifications of changed control signals via radioComRxControlSignals() 41 | * and receives data bytes via radioComRxAvailable() and radioComRxReceiveByte() in the 42 | * same order that these two pieces of information were received from the radio. 43 | * If this bit is 1, higher-level code must call radioComRxControlSignals() regularly, or 44 | * else it will not be able to receive bytes using 45 | * radioComRxAvailable() and radioComRxReceiveByte(). 46 | * 47 | * When this bit is 0, the higher-level code does not have to call radioComRxControlSignals() 48 | * regularly. 49 | * 50 | * We recommend that if you call radioComRxControlSignals(), you should call it regularly 51 | * and set #radioComRxEnforceOrdering to 1 at the beginning of your program. If you are not 52 | * using the control signals, you should leave this bit at 0. */ 53 | extern BIT radioComRxEnforceOrdering; 54 | 55 | /*! \return The number of bytes in the RX buffer. 56 | * 57 | * You can use this function to see if any bytes have been received, and then 58 | * use radioComRxReceiveByte() to actually get the byte and process it. */ 59 | uint8 radioComRxAvailable(void); 60 | 61 | /*! \return A byte from the RX buffer. 62 | * 63 | * Bytes are returned in the order they were received from the other Wixel. 64 | * 65 | * This is a non-blocking function: you must call radioComRxAvailable() before calling 66 | * this function and be sure not to read too many bytes. 67 | * The number of times you call this should not exceed the last value returned by 68 | * radioComRxAvailable(). */ 69 | uint8 radioComRxReceiveByte(void); 70 | 71 | /*! This function must be called regularly if you want to send data 72 | * or control signals to the other Wixel. */ 73 | void radioComTxService(void); 74 | 75 | /*! \return The number of bytes available in the TX buffer. */ 76 | uint8 radioComTxAvailable(void); 77 | 78 | /*! Adds a byte to the TX buffer, which means it will be eventually 79 | * sent to the other Wixel over the radio. 80 | * 81 | * \param byte The byte to send. 82 | * 83 | * This is a non-blocking function: you must call radioComTxAvailable() before calling this 84 | * function and be sure not to add too many bytes to the buffer. The number of times you call 85 | * this should not exceed the last value returned by radioComTxAvailable(). 86 | * 87 | * If you call this function, you must also call radioComTxService() regularly. */ 88 | void radioComTxSendByte(uint8 byte); 89 | 90 | /*! \param controlSignals The state of the eight virtual TX control signals. 91 | * Each bit represents a different control signal. 92 | * 93 | * The values of these eight control lines are transmitted to the 94 | * other Wixel. 95 | * 96 | * Note that these signals (the TX signals) are independent of the 97 | * signals received from the other Wixel (the RX signals). 98 | * 99 | * The meaning of these control signals (e.g. their mapping to RS-232 control 100 | * signals) is determined by higher-level code. */ 101 | void radioComTxControlSignals(uint8 controlSignals); 102 | 103 | /*! \return The state of the eight virtual RX control signals. 104 | * Each bit represents a different control signal. 105 | * 106 | * The values of these eight control lines are zero by default, 107 | * but they can be set wirelessly by the other Wixel. 108 | * 109 | * Note that these signals (the RX signals) are independent of the 110 | * signals transmitted to other Wixel (the TX signals). 111 | * 112 | * The meaning of these control signals (e.g. their mapping to RS-232 control 113 | * signals) is determined by higher-level code. */ 114 | uint8 radioComRxControlSignals(void); 115 | 116 | #endif /* RADIO_COM_H_ */ 117 | -------------------------------------------------------------------------------- /libraries/src/wixel/board.c: -------------------------------------------------------------------------------- 1 | // board.c: Basic function and variables for interacting with the 2 | // hardware on the Wixel. Includes LED, power detection, and common 3 | // timing/delay functions. 4 | 5 | // TODO: Allow for getting into bootloader mode when the yellow LED is on 6 | // (need to turn it off for a brief time). 7 | // TODO: only go into bootloader mode if there is USB power 8 | // TODO: add a section of the library for using the watchdog timer 9 | // TODO: let delayMicroseconds take a 16-bit argument 10 | // TODO: WHY does this interrupt only result in a 6 us pulse? 11 | // ISR(P0INT, 1) 12 | // { 13 | // P1_0 ^= 1; 14 | // delayMicroseconds(40); 15 | // P1_0 ^= 1; 16 | // } 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* vbusHigh: 0 if VBUS is low (USB not connected). 25 | * 1 if VBUS is high (USB connected). 26 | * This variable is updated by wixelDetectVbus(). */ 27 | static BIT vbusHighBit; 28 | 29 | void systemInit() 30 | { 31 | boardIoInit(); 32 | boardClockInit(); 33 | timeInit(); 34 | dmaInit(); 35 | } 36 | 37 | void boardService() 38 | { 39 | boardStartBootloaderIfNeeded(); 40 | } 41 | 42 | /* Starts up the external 48 MHz oscillator and configures 43 | * the processor to run at 24 MHz. 44 | */ 45 | void boardClockInit() 46 | { 47 | // OSC_PD=0: Power up both high-speed oscillators: XOSC and HS RCOSC. 48 | SLEEP &= ~0x04; 49 | 50 | // Wait until the high speed crystal oscillator is stable (SLEEP.XOSC_STB=1) 51 | // This condition is required to use the radio or USB. 52 | // According to Table 6.4.2, the waiting should take about 650 microseconds. 53 | while(!(SLEEP & 0x40)); 54 | 55 | // OSC32K = 1: Use low power 32kHz oscillator for the 32 kHz signal. 56 | // OSC=0: Select high speed crystal oscillator for system clock (24 MHz). 57 | // TICKSPD=000: Set the timer tick speed to its fastest possible value. 58 | // CLKSPD=000: Set system clock speed to its fastest possible value (24 MHz). 59 | // This is required for using the Forward Error Correction radio feature (which we don't use anymore). 60 | CLKCON = 0x80; 61 | 62 | // Power down the HS RCOSC (the one that is not currently selected by 63 | // CLKCON.OSC). 64 | SLEEP |= 0x04; 65 | 66 | // Enable pre-fetching of instructions from flash, 67 | // which makes the code execute much faster. 68 | MEMCTR = 0; 69 | } 70 | 71 | void boardIoInit() 72 | { 73 | P2DIR = 0; // Make all the Port 2 pins be inputs. 74 | P2 = 0b00000110; // P2_1 = 1: drive the red LED line high LATER (when LED_RED(1) is called) 75 | // P2_2 = 1: drive the yellow LED line high LATER (when LED_YELLOW(1) is called) 76 | // P2_4 = 0: drive the VBUS_IN/GREEN_LED line low LATER (when LED_GREEN(1) is called) 77 | P2INP = 0b10011001; // Pull down LED pins (P2_2, P2_1), and tristate the other Port 2 pins. 78 | } 79 | 80 | /* Checks to see if USB is connected (VBUS_IN line is high). 81 | * The check is only performed if it has not been performed within the last 25 milliseconds. 82 | * (USB spec says we have to detect power loss within 100 ms). 83 | * This function updates the bit variable vbusHigh. */ 84 | static void boardDetectVbus() 85 | { 86 | static uint8 lastCheck = 128; 87 | if ((uint8)(getMs() - lastCheck) > 25) 88 | { 89 | BIT savedState = (P2DIR >> 4) & 1; 90 | if (savedState == 0) 91 | { 92 | P2DIR |= (1<<4); // Drive the VBUS_IN low 93 | delayMicroseconds(2); 94 | } 95 | P2INP &= ~(1<<4); // Set input mode to pull-down 96 | P2DIR &= ~(1<<4); // Make the line an input. 97 | delayMicroseconds(1); 98 | 99 | vbusHighBit = P2_4; // Measure the voltage. 100 | 101 | P2INP |= (1<<4); // Set input mode to tristate. 102 | if (savedState) 103 | { 104 | P2DIR |= (1<<4); // LED was on previously so turn it back on. 105 | } 106 | 107 | lastCheck = getMs(); 108 | } 109 | } 110 | 111 | void boardStartBootloader() 112 | { 113 | EA = 0; // Disable interrupts. 114 | 115 | DMAARM = 0x9F; // Disarm all DMA channels. 116 | 117 | delayMicroseconds(10); // Probably not necessary anymore. Used to be 10 milliseconds. 118 | 119 | // Make all the IO lines be inputs. That's going to happen later in 120 | // the bootloader anyway. We might as well do it now so that any devices 121 | // such as motors stop running right away. This also signals to the USB host 122 | // that we are disconnecting. 123 | P0DIR = P1DIR = P2DIR = 0; 124 | P0SEL = P1SEL = P2SEL = 0; 125 | 126 | delayMs(100); // Delay to give the USB host a chance to detect that we disconnected. 127 | __asm ljmp 6 __endasm; 128 | } 129 | 130 | void boardStartBootloaderIfNeeded() 131 | { 132 | if (!(P2DIR & (1<<2))) // If the yellow LED is off... 133 | { 134 | delayMicroseconds(10); 135 | if (P2_2) 136 | { 137 | boardStartBootloader(); 138 | } 139 | } 140 | } 141 | 142 | BIT usbPowerPresent() 143 | { 144 | boardDetectVbus(); 145 | return vbusHighBit; 146 | } 147 | 148 | BIT vinPowerPresent() 149 | { 150 | return P2_3; // Read VIN_IN. 151 | } 152 | 153 | void disableUsbPullup() 154 | { 155 | P2DIR &= ~(1<<0); // Make P2_0 be a floating input. 156 | } 157 | 158 | void enableUsbPullup() 159 | { 160 | P2_0 = 1; 161 | P2DIR |= (1<<0); // Drive P2_0 high. 162 | } 163 | -------------------------------------------------------------------------------- /libraries/include/board.h: -------------------------------------------------------------------------------- 1 | /*! \file board.h 2 | * This file provides basic functions for manipulating the 3 | * hardware on the Wixel, such as the LEDs, power detection pins, 4 | * and the pullup on the USB D+ line. It also has functions 5 | * related to the Wixel's bootloader. The implementations of these 6 | * functions are in wixel.lib. 7 | */ 8 | 9 | #ifndef _WIXEL_H 10 | #define _WIXEL_H 11 | 12 | #include 13 | #include 14 | 15 | /*! The 32-bit serial number of this device. The Wixel's serial number is 16 | * stored in the bootloader's flash section. */ 17 | extern uint8 CODE serialNumber[4]; 18 | 19 | /*! The 32-bit serial number of this device represented in USB String 20 | * Descriptor format as specified in the USB Specification. */ 21 | extern uint16 CODE serialNumberStringDescriptor[]; 22 | 23 | /*! Turns the green LED on if the argument is non-zero, otherwise 24 | * turns it off. 25 | * Note that the green LED is powered from USB so it will not actually 26 | * emit light when the USB cable is disconnected. */ 27 | #define LED_GREEN(v) {((v) ? (P2DIR |= 0x10) : (P2DIR &= ~0x10));} 28 | 29 | /*! Turns the yellow LED on if the argument is non-zero, otherwise 30 | * turns it off. */ 31 | #define LED_YELLOW(v) {((v) ? (P2DIR |= 0x04) : (P2DIR &= ~0x04));} 32 | 33 | /*! Turns the red LED on if the argument is non-zero, otherwise 34 | * turns it off. */ 35 | #define LED_RED(v) {((v) ? (P2DIR |= 0x02) : (P2DIR &= ~0x02));} 36 | 37 | /*! \return 1 if the green LED is on, 0 otherwise. 38 | * 39 | * Note that the green LED is powered from USB so it will not actually emit 40 | * light when the USB cable is disconnected, but this macro may still return 41 | * 1 in that case. 42 | */ 43 | #define LED_GREEN_STATE ((P2DIR >> 4) & 1) 44 | 45 | /*! \return 1 if the yellow LED is on, 0 otherwise. */ 46 | #define LED_YELLOW_STATE ((P2DIR >> 2) & 1) 47 | 48 | /*! \return 1 if the red LED is on, 0 otherwise. */ 49 | #define LED_RED_STATE ((P2DIR >> 1) & 1) 50 | 51 | /*! Toggles the state of the green LED. 52 | * This is slightly more efficient than 53 | * LED_GREEN(!LED_GREEN_STATE); */ 54 | #define LED_GREEN_TOGGLE() {P2DIR ^= 0x10;} 55 | 56 | /*! Toggles the state of the yellow LED. 57 | * This is slightly more efficient than 58 | * LED_YELLOW(!LED_YELLOW_STATE); */ 59 | #define LED_YELLOW_TOGGLE() {P2DIR ^= 0x04;} 60 | 61 | /*! Toggles the state of the red LED. 62 | * This is slightly more efficient than 63 | * LED_RED(!LED_RED_STATE); */ 64 | #define LED_RED_TOGGLE() {P2DIR ^= 0x02;} 65 | 66 | /*! Initializes the board's I/O lines, clock and other basic things. 67 | * You will typically want to call this function at the very beginning 68 | * of main() before you do anything else. 69 | * This is a simple function which just calls several other initialization 70 | * functions so you can look at the documentation of those other functions 71 | * to find out exactly what this one does. 72 | * 73 | * This function calls: 74 | * 75 | * -# boardIoInit() 76 | * -# boardClockInit() 77 | * -# timeInit() 78 | * -# dmaInit() 79 | */ 80 | void systemInit(); 81 | 82 | /*! Initializes the board's I/O lines. Specifically, this function: 83 | * - Initializes the P2 register. 84 | * - Enables pull-down resistors for the red and yellow LED pins and 85 | * disables pull-down resistors for the other port 2 pins. 86 | * 87 | * This function is called by systemInit(). 88 | */ 89 | void boardIoInit(); 90 | 91 | /*! Initializes the board's clock and conifgures the CPU and the 92 | * timers to run as fast as possible. 93 | * 94 | * This function is called by systemInit(). 95 | * */ 96 | void boardClockInit(); 97 | 98 | /*! Takes care of any board-related tasks that need to be performed 99 | * regularly. 100 | * Right now all this function does is call boardStartBootloaderIfNeeded() 101 | * so you should call this function regularly if you want to be able to 102 | * jump to the bootloader from the application by shorting P2_2 to 3V3. */ 103 | void boardService(); 104 | 105 | /*! Checks to see if the yellow LED line (P2_2) is connected to 3V3. 106 | * If they are connected, then it starts the bootloader by calling 107 | * boardStartBootloader. 108 | * This function is called by boardService. 109 | * If you call this function regularly, then it provides a relatively 110 | * easy way to get into bootloader mode if you can't do it with a 111 | * USB command. 112 | * Currently this function only works while the yellow LED is off. */ 113 | void boardStartBootloaderIfNeeded(); 114 | 115 | /*! Shuts down the application and starts the bootloader. */ 116 | void boardStartBootloader(); 117 | 118 | /*! \return 1 if USB power (VBUS) is detected, 0 otherwise. 119 | * 120 | * This function relies on getMs, so you must call timeInit() before 121 | * calling this. If this function returns 1, it means that the USB 122 | * cable is plugged in. */ 123 | BIT usbPowerPresent(); 124 | 125 | /*! \return 1 if VIN power is detected, 0 otherwise. */ 126 | BIT vinPowerPresent(); 127 | 128 | /*! Enables the 1500 &Ohm; pull-up the USB D+ line. This 129 | * signals to the USB host that a device has been attached. 130 | * This function is called by usb.lib (see usb.h); 131 | * if you are using that library you should not call this 132 | * function yourself. */ 133 | void enableUsbPullup(); 134 | 135 | /*! Disables the 1500 &Ohm; pull-up the USB D+ line. This 136 | * signals to the USB host that this device has been detached. 137 | * This function is called by usb.lib (see usb.h); 138 | * if you are using that library you should not call this 139 | * function yourself. */ 140 | void disableUsbPullup(); 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /libraries/include/usb_hid_constants.h: -------------------------------------------------------------------------------- 1 | /*! \file usb_hid_constants.h 2 | * This file contains definitions of constants used in HID reports sent by the 3 | * usb_hid.lib library. These are Usage tags that are specified in 4 | * in Hut1_12.pdf, available for download from USB Implementers Forum at this 5 | * url: 6 | * http://www.usb.org/developers/hidpage 7 | */ 8 | 9 | #ifndef USB_HID_CONSTANTS_H_ 10 | #define USB_HID_CONSTANTS_H_ 11 | 12 | // Bits in usbHidKeyboardOutput.leds 13 | #define LED_NUM_LOCK 0 14 | #define LED_CAPS_LOCK 1 15 | #define LED_SCROLL_LOCK 2 16 | #define LED_COMPOSE 3 17 | #define LED_KANA 4 18 | #define LED_POWER 5 19 | #define LED_SHIFT 6 20 | #define LED_DO_NOT_DISTURB 7 21 | 22 | // Bits in usbHidKeyboardInput.modifiers 23 | #define MODIFIER_CONTROL_LEFT 0 24 | #define MODIFIER_SHIFT_LEFT 1 25 | #define MODIFIER_ALT_LEFT 2 26 | #define MODIFIER_GUI_LEFT 3 27 | #define MODIFIER_CONTROL_RIGHT 4 28 | #define MODIFIER_SHIFT_RIGHT 5 29 | #define MODIFIER_ALT_RIGHT 6 30 | #define MODIFIER_GUI_RIGHT 7 31 | 32 | // Values for usbHidKeyboardInput.keyCodes 33 | // Only the key codes for common keys are defined here. See Hut1_12.pdf for a full list. 34 | #define KEY_NONE 0x00 35 | #define KEY_A 0x04 36 | #define KEY_B 0x05 37 | #define KEY_C 0x06 38 | #define KEY_D 0x07 39 | #define KEY_E 0x08 40 | #define KEY_F 0x09 41 | #define KEY_G 0x0A 42 | #define KEY_H 0x0B 43 | #define KEY_I 0x0C 44 | #define KEY_J 0x0D 45 | #define KEY_K 0x0E 46 | #define KEY_L 0x0F 47 | #define KEY_M 0x10 48 | #define KEY_N 0x11 49 | #define KEY_O 0x12 50 | #define KEY_P 0x13 51 | #define KEY_Q 0x14 52 | #define KEY_R 0x15 53 | #define KEY_S 0x16 54 | #define KEY_T 0x17 55 | #define KEY_U 0x18 56 | #define KEY_V 0x19 57 | #define KEY_W 0x1A 58 | #define KEY_X 0x1B 59 | #define KEY_Y 0x1C 60 | #define KEY_Z 0x1D 61 | #define KEY_1 0x1E 62 | #define KEY_2 0x1F 63 | #define KEY_3 0x20 64 | #define KEY_4 0x21 65 | #define KEY_5 0x22 66 | #define KEY_6 0x23 67 | #define KEY_7 0x24 68 | #define KEY_8 0x25 69 | #define KEY_9 0x26 70 | #define KEY_0 0x27 71 | #define KEY_RETURN 0x28 72 | #define KEY_ESCAPE 0x29 73 | #define KEY_BACKSPACE 0x2A 74 | #define KEY_TAB 0x2B 75 | #define KEY_SPACE 0x2C 76 | #define KEY_MINUS 0x2D 77 | #define KEY_EQUAL 0x2E 78 | #define KEY_BRACKET_LEFT 0x2F 79 | #define KEY_BRACKET_RIGHT 0x30 80 | #define KEY_BACKSLASH 0x31 81 | #define KEY_EUROPE_1 0x32 82 | #define KEY_SEMICOLON 0x33 83 | #define KEY_APOSTROPHE 0x34 84 | #define KEY_GRAVE 0x35 85 | #define KEY_COMMA 0x36 86 | #define KEY_PERIOD 0x37 87 | #define KEY_SLASH 0x38 88 | #define KEY_CAPS_LOCK 0x39 89 | #define KEY_F1 0x3A 90 | #define KEY_F2 0x3B 91 | #define KEY_F3 0x3C 92 | #define KEY_F4 0x3D 93 | #define KEY_F5 0x3E 94 | #define KEY_F6 0x3F 95 | #define KEY_F7 0x40 96 | #define KEY_F8 0x41 97 | #define KEY_F9 0x42 98 | #define KEY_F10 0x43 99 | #define KEY_F11 0x44 100 | #define KEY_F12 0x45 101 | #define KEY_PRINT_SCREEN 0x46 102 | #define KEY_SCROLL_LOCK 0x47 103 | #define KEY_PAUSE 0x48 104 | #define KEY_INSERT 0x49 105 | #define KEY_HOME 0x4A 106 | #define KEY_PAGE_UP 0x4B 107 | #define KEY_DELETE 0x4C 108 | #define KEY_END 0x4D 109 | #define KEY_PAGE_DOWN 0x4E 110 | #define KEY_ARROW_RIGHT 0x4F 111 | #define KEY_ARROW_LEFT 0x50 112 | #define KEY_ARROW_DOWN 0x51 113 | #define KEY_ARROW_UP 0x52 114 | #define KEY_NUM_LOCK 0x53 115 | #define KEY_KEYPAD_DIVIDE 0x54 116 | #define KEY_KEYPAD_MULTIPLY 0x55 117 | #define KEY_KEYPAD_SUBTRACT 0x56 118 | #define KEY_KEYPAD_ADD 0x57 119 | #define KEY_KEYPAD_ENTER 0x58 120 | #define KEY_KEYPAD_1 0x59 121 | #define KEY_KEYPAD_2 0x5A 122 | #define KEY_KEYPAD_3 0x5B 123 | #define KEY_KEYPAD_4 0x5C 124 | #define KEY_KEYPAD_5 0x5D 125 | #define KEY_KEYPAD_6 0x5E 126 | #define KEY_KEYPAD_7 0x5F 127 | #define KEY_KEYPAD_8 0x60 128 | #define KEY_KEYPAD_9 0x61 129 | #define KEY_KEYPAD_0 0x62 130 | #define KEY_KEYPAD_DECIMAL 0x63 131 | #define KEY_EUROPE_2 0x64 132 | #define KEY_APPLICATION 0x65 133 | #define KEY_POWER 0x66 134 | #define KEY_KEYPAD_EQUAL 0x67 135 | #define KEY_F13 0x68 136 | #define KEY_F14 0x69 137 | #define KEY_F15 0x6A 138 | #define KEY_CONTROL_LEFT 0xE0 139 | #define KEY_SHIFT_LEFT 0xE1 140 | #define KEY_ALT_LEFT 0xE2 141 | #define KEY_GUI_LEFT 0xE3 142 | #define KEY_CONTROL_RIGHT 0xE4 143 | #define KEY_SHIFT_RIGHT 0xE5 144 | #define KEY_ALT_RIGHT 0xE6 145 | #define KEY_GUI_RIGHT 0xE7 146 | 147 | // Bits in usbHidMouseInput.buttons 148 | #define MOUSE_BUTTON_LEFT 0 149 | #define MOUSE_BUTTON_RIGHT 1 150 | #define MOUSE_BUTTON_MIDDLE 2 151 | 152 | #endif /* USB_HID_CONSTANTS_H_ */ 153 | -------------------------------------------------------------------------------- /libraries/include/radio_mac.h: -------------------------------------------------------------------------------- 1 | /*! \file radio_mac.h 2 | * The radio_mac.lib library takes care of sending and 3 | * receiving packets. 4 | * It handles the details of setting up the radio interrupt and 5 | * DMA configuration. 6 | * It uses radio_registers.lib to configure the radio. 7 | * 8 | * When a radio-related event happens, radio_mac.lib 9 | * reports the event to higher-level code by calling radioMacEventHandler() 10 | * in an ISR. The higher-level code can then decide what to do next by 11 | * calling radioMacTx() or radioMacRx() from the event handler. 12 | * 13 | * This library does not currently support any way of turning off the 14 | * radio to save power. 15 | * 16 | * This library defines an ISR, so radio_mac.h must be included in the 17 | * file that defines main() in order for this library to work. 18 | * 19 | * This library uses an interrupt. 20 | * For this library to work, you must write 21 | * include 22 | * in the source file that contains your main() function. 23 | */ 24 | 25 | #ifndef _RADIO_MAC_H_ 26 | #define _RADIO_MAC_H_ 27 | 28 | #include 29 | #include 30 | 31 | /*! See the documentation for radioMacEventHandler(). */ 32 | #define RADIO_MAC_EVENT_TX 30 33 | /*! See the documentation for radioMacEventHandler(). */ 34 | #define RADIO_MAC_EVENT_RX 31 35 | /*! See the documentation for radioMacEventHandler(). */ 36 | #define RADIO_MAC_EVENT_RX_TIMEOUT 32 37 | /*! See the documentation for radioMacEventHandler(). */ 38 | #define RADIO_MAC_EVENT_STROBE 33 39 | 40 | /*! Initializes the radio. 41 | * This involves calling radioRegistersInit(). 42 | * This should be called before any other radioMac functions are called. */ 43 | void radioMacInit(void); 44 | 45 | /*! Forces the radioMacEventHandler() to run soon. 46 | * 47 | * This function triggers an artificial radio interrupt. 48 | * If the radio is not in the middle of transmitting, receiving, 49 | * or waiting for a packet with a short RX timeout, then 50 | * radioMacEventHandler() will be called with an argument of 51 | * RADIO_MAC_EVENT_STROBE. 52 | * Otherwise, radioMacStrobe will be called soon with a different 53 | * argument. 54 | * 55 | * The idea behind this function is that higher-level code running 56 | * in the main loop would call it whenever it has placed new 57 | * data into a buffer, in order to wake up the interrupt-based 58 | * code to so it can use the new data. */ 59 | void radioMacStrobe(void); 60 | 61 | /*! Shutdown the radio in preparation for sleep. 62 | * 63 | * This function sets a shutdown bit then triggers the strobe 64 | * if there are tx or rx transactions that are close to completion 65 | * they will be allowed to complete. The current radioMacState will 66 | * be saved and will be started in that state when resumed. 67 | * 68 | * The function will spin wait till the radio state changes to IDLE. */ 69 | void radioMacSleep(void); 70 | 71 | /*! Resume the radio operation after sleep. 72 | * 73 | * This function will resume operation of the radio 74 | * The radio will start in the same state that it was in 75 | * when it was suspended */ 76 | void radioMacResume(void); 77 | 78 | /*! Sets up the radio to transmit a packet. 79 | * 80 | * \param packet A pointer to the packet to transmit. 81 | * The first byte (packet[0]) should be the length of the payload in bytes. 82 | * The payload should start at packet[1]. 83 | * 84 | * This function will only work if it is called from radioMacEventHandler(). */ 85 | void radioMacTx(uint8 XDATA * packet); 86 | 87 | /*! Sets up the radio to receive a packet. 88 | * 89 | * \param packet A pointer to the location to store the packet. 90 | * \param timeout The timeout period, in units of 1 ms. 91 | * If a packet has not been received in this time, then a 92 | * RADIO_MAC_EVENT_RX_TIMEOUT event will happen. 93 | * Set this parameter to 0 to disable the timeout. 94 | * 95 | * Later, after the packet has been received, packet[0] will contain the 96 | * length of the packet payload in bytes, and the payload will 97 | * start at packet[1]. 98 | * Also, two status bytes will be appended at the end of the packet 99 | * as described in Tables 64 and 65 of the CC2511 datasheet. 100 | */ 101 | void radioMacRx(uint8 XDATA * packet, uint8 timeout); 102 | 103 | /*! This is a callback function that should be defined by higher-level code. 104 | * 105 | * This function is called in the RF ISR whenever a radio-related event happens. 106 | * This function should decide what the radio will do next by calling either 107 | * radioMacTx() or radioMacRx(). 108 | * 109 | * \param event The event that just happened. This will be one of: 110 | * - #RADIO_MAC_EVENT_TX: The radio just finished transmitting a packet. 111 | * - #RADIO_MAC_EVENT_RX: The radio just finished receiving a packet. 112 | * - #RADIO_MAC_EVENT_RX_TIMEOUT: The radio was listening for a packet and 113 | * nothing was received within the timeout period. 114 | * - #RADIO_MAC_EVENT_STROBE: The function radioMacStrobe() was called. 115 | * 116 | * Note: Not every call to radioMacStrobe() results in a call to 117 | * radioMacEventHandler with argument RADIO_MAC_EVENT_STROBE. 118 | * 119 | * See radio_queue.c or radio_link.c for examples of how to define 120 | * radioMacEventHandler(). 121 | */ 122 | void radioMacEventHandler(uint8 event); 123 | 124 | /*! The library will set this bit to 1 when an RX overflow occurs. 125 | * 126 | * An RX overflow is an error that indicates that incoming data was 127 | * not read from the radio fast enough. 128 | * This should not happen. 129 | */ 130 | extern volatile BIT radioRxOverflowOccurred; 131 | 132 | /*! The library will set this bit to 1 when a TX underflow occurs. 133 | * 134 | * A TX underflow is an error that indicates that outgoing data was 135 | * not written to the radio fast enough. 136 | * This should not happen. */ 137 | extern volatile BIT radioTxUnderflowOccurred; 138 | 139 | /*! The radio's Interrupt Service Routine (ISR). */ 140 | ISR(RF, 0); 141 | 142 | #endif /* RADIO_H_ */ 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | xDrip for Wixel 2 | ================= 3 | 4 | ### What is it? 5 | This project can be loaded onto a wixel, it will catch the wireless signals 6 | sent from a dexcom transmitter, read, break up the different parts, and then send it using UART so it can be 7 | retransmitted through Bluetooth 8 | 9 | ### How do I use it? 10 | Its easy! 11 | * step 1: Clone the repo! 12 | * Using Git: 13 | `git clone https://github.com/StephenBlackWasAlreadyTaken/wixel-xDrip.git` 14 | * Scared of Git? 15 | Download the 16 | [ZIP](https://github.com/StephenBlackWasAlreadyTaken/wixel-xDrip/archive/master.zip) and unpack it! 17 | 18 | * step 2: Install the Wixel drivers and software 19 | * You can find them [here!](http://www.pololu.com/docs/0J46/3) 20 | 21 | * step 2.5: Modify the top section of the file `apps/xdrip/xdrip.c` to fit 22 | your needs 23 | * Likely you will want to enter your actual transmitter id (Should only be numbers and **CAPITAL LETTERS** , and set 24 | `only_listen_to_my_transmitter` to 1. 25 | * Leaving `status_lights = 1` will blink the yellow light whenever it is searching for a packet (also you may notice a faint red blink when it strobes the radio) Setting it to zero will make it not blink (the red strobe will still happen though) 26 | * The USB enabled and close options have been removed, instead the wixel will detect its usb state every time it wakes up to scan for packets. This means if you plug in the wixel your computer may not see it for a few minutes (5) * if for some reason you still cant get your computer to recognize it, touch a wire from RST to GND 27 | * If you did something crazy and locked up the bootloader, you will need to jump the wixel into BootLoader mode. see 28 | [this](http://www.pololu.com/docs/0J46/5.c) for instructions on getting the 29 | wixel back into bootloader mode. 30 | 31 | 32 | * step 3: Run the MAKE command to generate a file you can install on your Wixel 33 | 34 | ##### ON A MAC 35 | * If you do not already have sdcc, you will need to do the following (not sure? open a terminal and run `sdcc -v` if you get the error `sdcc: command not found` then you need to install it! 36 | * Open a new terminal (if you cant find terminal, just search for it in spotlight) then run the following commands (just coppy and paste this whole big ol thing) 37 | 38 | `curl -O http://sourceforge.net/projects/sdcc/files/sdcc-macosx/3.4.0/sdcc-3.4.0-universal-apple-macosx.tar.bz2 -L; tar xjf sdcc-3.4.0-universal-apple-macosx.tar.bz2; cd sdcc-3.4.0/bin; sudo cp -r -n * /usr/bin; cd ../share/sdcc;sudo mkdir /usr/share/sdcc;sudo cp -r -n * /usr/share/sdcc;` 39 | * it should ask for your password, just type in your macs password and hit enter (Note that you will not see anything while typing the password) 40 | * Cool, now if you run `sdcc -v` you should see something like `SDCC : mcs51/z80/z180....` 41 | 42 | * Now back to our wixel app! 43 | * In your terminal/command prompt head to the directory where you cloned/unzipped this repo. 44 | * Run `make` 45 | * If you dont already have Command line tools installed it will ask you if you want to install them, just say yes and let it do its thing (note, on a mac version earlier than maverics, you will need to download xcode manually in order to install command line tools) 46 | * If successfull you should see a lot of lines that end something like 47 | ``` 48 | Linking apps/xdrip/xdrip.hex 49 | Packaging apps/xdrip/xdrip.wxl 50 | packihx: read 413 lines, wrote 779: OK. 51 | ``` 52 | ##### ON UBUNTU-LINUX (14.04 or later, should also work on Debian Jessie or later) 53 | * If you don't already have SDCC installed, open a terminal and run the command 'sudo apt-get install sdcc' and follow the instructions on screen (enter password, confirm with 'y', ...). (Not sure if installed?: run 'sdcc -v'. If the result is '/usr/bin/sdcc: No such file or directory', install it.) 54 | * If it is installed, the version number returned on the command 'sdcc -v' should be at least 3.3.0 55 | * From now on, you can follow the instructions for MAC starting from "Now back to our wixel app!". 56 | 57 | ##### ON WINDOWS 58 | * Install the wixel development bundle for windows from [here](http://www.pololu.com/file/0J526/wixel-dev-bundle-120127.exe) (you need this in addition to the drivers you downloaded in step 2!!) 59 | * Open a command prompt (should be under start menu -> programs -> accessories -> Command Prompt) 60 | * Cd into the folder you downloaded this repo to (ex. `cd C:\Users\\Desktop\wixel-xDrip`) 61 | * now run `make_all.bat` by typing `make_all.bat` into the command prompt 62 | 63 | 64 | * You should see a lot of lines that end something like 65 | ``` 66 | Linking apps/xdrip/xdrip.hex 67 | Packaging apps/xdrip/xdrip.wxl 68 | packihx: read 413 lines, wrote 779: OK. 69 | ``` 70 | * step 4: Load the app 71 | * plug your wixel in to your computer and follow [these steps](http://www.pololu.com/docs/0J46/3.d) to install your app! 72 | 73 | * step 5: Done with this part! Now hook it up to something!!! 74 | 75 | 76 | ##### NOTE: 77 | The wixel will transmit the data out over uart using pins p1_6 and p1_7 at a 78 | baud rate of 9600, feel free to change that in the code if you need. 79 | 80 | 81 | # HUGE PROPS TO: 82 | Adrien De Croy for writing most of this for his Dexterity Prject! 83 | 84 | Lorelai for pointing me to all of these great resources and then also allowing me to use large portions of her code. 85 | 86 | John Stevens for further improving on Adrians code, which I also then used!! 87 | 88 | 89 | Wow.. Im begining to think I didnt do anything other than copy and paste these peoples works... 90 | 91 | 92 | Don Brown over at [dexwatch](http://dexwatch.blogspot.com/) for initially pointing 93 | out that this is a possibility to me! 94 | 95 | Ben West, John Costik and Scott Leibrand their awesome work with Nightscout and various other projects! 96 | 97 | And all the other awesome people that helped me out and contributed to awesome projects like NightScout 98 | 99 | 100 | # LINKS 101 | * [Project Site](http://stephenblackwasalreadytaken.github.io/xDrip/) 102 | * [What you will need & Diagrams](https://github.com/StephenBlackWasAlreadyTaken/xDrip/blob/gh-pages/hardware_setup.md) 103 | * [Wixel App](https://github.com/StephenBlackWasAlreadyTaken/wixel-xDrip) 104 | * [Android App](https://github.com/StephenBlackWasAlreadyTaken/xDrip) 105 | -------------------------------------------------------------------------------- /libraries/include/spi0_master.h: -------------------------------------------------------------------------------- 1 | /*! \file spi0_master.h 2 | * 3 | * The spi_master.lib library allows you to do SPI master 4 | * communication using USART0 and/or USART1. 5 | * This library uses interrupts to transfer data so it is capable of 6 | * sending/receiving in the background while other tasks are performed. 7 | * 8 | * To use this library, you must include spi0_master.h or spi1_master.h 9 | * in your app: 10 | \code 11 | #include 12 | #include 13 | \endcode 14 | * 15 | * Since this library uses interrupts, the include statement must be present 16 | * in the file that contains main(). 17 | * 18 | * The API for using USART1 is the same as the API for using USART0 that is 19 | * documented here, except all the function and variable names begin with 20 | * "spi1Master" instead of "spi0Master". 21 | * 22 | * For USART0, this library uses Alternative Location 1: P0_5 is SCK, 23 | * P0_3 is MOSI, and P0_2 is MISO. 24 | * 25 | * For USART1, this library uses Alternative Location 2: P1_5 is SCK, 26 | * P1_6 is MOSI, P1_7 is MISO. 27 | * 28 | * This library does not yet allow you to choose which alternative 29 | * location to use. 30 | * 31 | * Please note that this library only supports SPI master 32 | * communication; MOSI and SCK are outputs and MISO is an input. 33 | */ 34 | 35 | #ifndef _SPI0_MASTER_H 36 | #define _SPI0_MASTER_H 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | /*! Initializes the library. 43 | * 44 | * This must be called before any other functions with names that 45 | * begin with "spi0Master". 46 | * 47 | * After calling this, it is recommended to call 48 | * spi0MasterSetFrequency(), spi0MasterSetClockPolarity(), 49 | * spi0MasterSetClockPhase(), and spi0MasterSetBitOrder() 50 | * to set the other parameters of the SPI communication. 51 | */ 52 | void spi0MasterInit(void); 53 | 54 | /*! Sets the frequency of the clock signal on SCK. 55 | * 56 | * \param freq The frequency, in bits per second. Must be between 23 and 3,000,000. 57 | */ 58 | void spi0MasterSetFrequency(uint32 freq); 59 | 60 | /*! Sets the clock polarity (the bit named CPOL in U0GCR). 61 | * This bit can be used to invert the signal on SCK. 62 | * Valid values are: 63 | * 64 | * - #SPI_POLARITY_IDLE_LOW (0): The SCK line will be low 65 | * when no data is being transferred. 66 | * - #SPI_POLARITY_IDLE_HIGH (1): The SCK line will be high 67 | * when no data is being transferred. 68 | * 69 | * For more information, see Figure 41 (SPI Dataflow) in the 70 | * CC2511F32 datasheet. 71 | */ 72 | void spi0MasterSetClockPolarity(BIT polarity); 73 | 74 | /*! Sets the clock phase (the bit named CPHA in U0GCR). 75 | * This bit controls the phase of the clock, 76 | * which determines what type of transition is occurring when 77 | * the data is sampled/transmitted. 78 | * Valid values are: 79 | * 80 | * - #SPI_PHASE_EDGE_LEADING (0): Data is sampled/transmitted 81 | * on the leading edge, when the clock line transitions 82 | * from idle to active. 83 | * - #SPI_PHASE_EDGE_TRAILING (1): Data is sampled/transmitted 84 | * on the trailing edge, when the clock like transitions 85 | * from active to idle. 86 | * 87 | * For more information, see Figure 41 (SPI Dataflow) in the 88 | * CC2511F32 datasheet. */ 89 | void spi0MasterSetClockPhase(BIT phase); 90 | 91 | /*! Sets the bit order for transfers. 92 | * Valid values are: 93 | * 94 | * - #SPI_BIT_ORDER_MSB_FIRST: The most-significant bit is transmitted first. 95 | * - #SPI_BIT_ORDER_LSB_FIRST: The least-significant bit is transmitted first. */ 96 | void spi0MasterSetBitOrder(BIT bitOrder); 97 | 98 | /*! \return 1 if the library is busy transferring of data, 0 if it 99 | is not busy. 100 | 101 | This is equivalent to spi0MasterBytesLeft() != 0 102 | but it is faster and doesn't affect the speed of the transfer. */ 103 | BIT spi0MasterBusy(void); 104 | 105 | /*! \return The number of bytes left to transfer in the current transfer. 106 | * If 0, it means there is no current transfer. 107 | * 108 | * This function temporarily disables the interrupt used by this library 109 | * to transfer data, so calling this function frequently could reduce the 110 | * speed that data is transferred. 111 | * If possible, try to use spi0MasterBusy() instead of this function. */ 112 | uint16 spi0MasterBytesLeft(void); 113 | 114 | /*! Starts a new transfer of data. 115 | * The transfer will be carried out in the background by interrupts, allowing 116 | * other tasks to be performed simultaneously. 117 | * This is a non-blocking function. 118 | * 119 | * \param txBuffer A pointer to a buffer holding the bytes to be sent to the SPI slave. 120 | * \param rxBuffer A pointer to a buffer to hold bytes received by the SPI slave 121 | * during this transfer. This may be equal to txBuffer, which would cause the 122 | * transmitted data to be overwritten with received data. 123 | * \param size The number of bytes to transmit/receive. 124 | * 125 | * This function should not be called if the library is busy doing a transfer 126 | * (i.e. spi0MasterBusy() returns 1). 127 | * 128 | * In SPI, every transfer of data consists of one byte going from the master to 129 | * the slave and one byte going from the slave to the master. 130 | * Not every byte is meaningful: often dummy data is inserted. 131 | * This function initiates a transmission of several bytes from the master 132 | * (the Wixel) to the slave. 133 | * During this transmission, an equal number of bytes will be received 134 | * and stored in the RX buffer. */ 135 | void spi0MasterTransfer(const uint8 XDATA * txBuffer, uint8 XDATA * rxBuffer, uint16 size); 136 | 137 | /*! Transmits one byte to the SPI slave, simultaneously receiving a byte from 138 | * the slave. This is a synchronous, blocking function so be careful about using 139 | * it in apps that have regular tasks to perform. 140 | * 141 | * This function should not be called if the library is busy doing a transfer 142 | * (i.e. spi0MasterBusy() returns 1). 143 | * 144 | * \param byte The byte to send to the slave. 145 | * \return The byte received from the slave. 146 | */ 147 | uint8 spi0MasterSendByte(uint8 XDATA byte); 148 | 149 | /*! This is equivalent to: 150 | \code 151 | spi0MasterSendByte(0xFF) 152 | \endcode 153 | */ 154 | uint8 spi0MasterReceiveByte(void); 155 | 156 | /*! A prototype for the USART0 interrupt. */ 157 | ISR(URX0, 0); 158 | 159 | #endif /* SPI0_MASTER_H_ */ 160 | -------------------------------------------------------------------------------- /libraries/include/usb_com.h: -------------------------------------------------------------------------------- 1 | /*! \file usb_com.h 2 | * The usb_com.lib library implements a virtual COM/serial port 3 | * over USB using the CDC ACM class. See also com.h. 4 | */ 5 | 6 | #ifndef _USB_COM_H 7 | #define _USB_COM_H 8 | 9 | #include 10 | #include 11 | 12 | typedef void (HandlerFunction)(void); 13 | 14 | /*! This function returns the current state of the virtual 15 | * RTS and DTR control lines. 16 | * The states of these lines are controlled by the USB Host. 17 | * 18 | * The default values are RTS=0 and DTR=0. In Windows, when a typical 19 | * terminal program opens the COM port, both RTS and DTR go to 1. When 20 | * the program closes the port, DTR goes to 0 but RTS remains at 1. 21 | * 22 | * The bits of this byte are defined in com.h: 23 | * - Bit 0: #ACM_CONTROL_LINE_DTR 24 | * - Bit 1: #ACM_CONTROL_LINE_RTS 25 | * - Bit 2-7: Reserved (should always be zero) 26 | * 27 | * Example: 28 | \code 29 | if (usbComRxControlSignals() & ACM_CONTROL_LINE_DTR) 30 | { 31 | // DTR is 1, which traditionally means the DTE (host) is present. 32 | } 33 | else 34 | { 35 | // DTR is 0, which traditionally means the DTE (host) is not present. 36 | } 37 | if (usbComRxControlSignals() & ACM_CONTROL_LINE_RTS) 38 | { 39 | // RTS is 1, which traditionally means "Activate carrier" or 40 | // tells DCE (device) to prepare to accept data from DTE (host). 41 | } 42 | else 43 | { 44 | // RTS is 0, which traditionally means "Deactivate carrier". 45 | } 46 | \endcode 47 | */ 48 | uint8 usbComRxControlSignals(void); 49 | 50 | /*! Sets the state of the virtual CD and DSR control lines. 51 | * The value of these lines control lines are reported back to the 52 | * USB host. 53 | * 54 | * The valid bits of the \p signals parameter are defined in com.h: 55 | * - Bit 0: #ACM_SERIAL_STATE_RX_CARRIER, a.k.a. CD or CdHolding 56 | * - Bit 1: #ACM_SERIAL_STATE_TX_CARRIER, a.k.a. DSR or DsrHolding 57 | * - Bit 2-7: Reserved (should be zero). 58 | * */ 59 | void usbComTxControlSignals(uint8 signals); 60 | 61 | /*! Allows you to report certain events to the USB host. 62 | * Unlike CD and DSR, which represent the state of a control line, 63 | * these represent events that happen at a particular 64 | * time. 65 | * 66 | * The valid bits of the \p signalEvents parameter are defined in com.h: 67 | * - Bit 2: #ACM_SERIAL_STATE_BREAK 68 | * - Bit 3: #ACM_SERIAL_STATE_RING_SIGNAL 69 | * - Bit 4: #ACM_SERIAL_STATE_FRAMING 70 | * - Bit 5: #ACM_SERIAL_STATE_PARITY 71 | * - Bit 6: #ACM_SERIAL_STATE_OVERRUN 72 | * - Bits 0, 1, and 7: Reserved (should be zero). 73 | * 74 | * You can report multiple events with one call to this function. 75 | * 76 | * Example use: 77 | \code 78 | if (uart0RxParityErrorOccurred) 79 | { 80 | // A parity error occurred on UART 1. 81 | uart0RxParityErrorOccurred = 0; // Clear the flag. 82 | usbComTxControlSignalEvents(ACM_SERIAL_STATE_PARITY); // Report it to the USB host. 83 | } 84 | \endcode 85 | */ 86 | void usbComTxControlSignalEvents(uint8 signalEvents); 87 | 88 | /*! The current line coding. This includes information such as the desired baud rate, 89 | * and is controlled by the USB host. */ 90 | extern ACM_LINE_CODING XDATA usbComLineCoding; 91 | 92 | /*! A pointer to a function that will be called whenever #usbComLineCoding gets set 93 | * by the USB host. */ 94 | extern HandlerFunction * usbComLineCodingChangeHandler; 95 | 96 | /*! This function should be called regularly (at least every 50 ms) if you are 97 | * using this library. 98 | * One of the things this function does is call usbPoll(). */ 99 | void usbComService(void); // This should be called regularly. 100 | 101 | /*! \return The number of bytes in the RX buffer that can be received 102 | * immediately. 103 | * 104 | * You can use this function to see if any bytes have been received, and then 105 | * use usbComRxReceiveByte() to actually get the byte and process it. 106 | * 107 | * The return value of this function might be lower than the actual number of 108 | * bytes that the USB host is trying to send. 109 | * Higher-level code should not count on the return value of this function 110 | * reaching anything higher than 1. */ 111 | uint8 usbComRxAvailable(void); 112 | 113 | /*! \return A byte from the RX buffer. 114 | * 115 | * Bytes are returned in the order they were received from the USB host. 116 | * 117 | * This is a non-blocking function: you must call usbComRxAvailable() before calling 118 | * this function and be sure not to read too many bytes. 119 | * The number of times you call this should not exceed the last value returned by 120 | * usbComRxAvailable(). */ 121 | uint8 usbComRxReceiveByte(void); 122 | 123 | /*! Reads the specified number of bytes from USB and stores them in memory. 124 | * 125 | * \param buffer The buffer to store the data in. 126 | * \param size The number of bytes to read. 127 | * 128 | * This is a non-blocking function: you must call usbComRxAvailable() before calling 129 | * this function and be sure not to read too many bytes. 130 | * The \p size parameter should not exceed the last value returned by 131 | * usbComRxAvailable(). 132 | * 133 | * See also usbComRxReceiveByte(). */ 134 | void usbComRxReceive(uint8 XDATA * buffer, uint8 size); 135 | 136 | /*! \return The number of bytes available in the TX buffers. 137 | * 138 | * The usb_cdc_acm.lib library uses a double-buffered endpoint 139 | * with 64-byte buffers, so if the USB host keeps reading data from the device 140 | * then this function will eventually return 128. */ 141 | uint8 usbComTxAvailable(void); 142 | 143 | /*! Adds a byte to the TX buffer, which means it will be eventually 144 | * sent to the USB host. 145 | * 146 | * \param byte The byte to send. 147 | * 148 | * This is a non-blocking function: you must call usbComTxAvailable() before calling this 149 | * function and be sure not to add too many bytes to the buffer. The number of times you call 150 | * this should not exceed the last value returned by usbComTxAvailable(). */ 151 | void usbComTxSendByte(uint8 byte); 152 | 153 | /*! Adds bytes to the TX buffers, which means they will be eventually 154 | * sent to the USB host. 155 | * 156 | * \param buffer A pointer to the bytes to send. 157 | * \param size The number of bytes to send. 158 | * 159 | * This is a non-blocking function: you must call usbComTxAvailable() before calling this 160 | * function and be sure not to add too many bytes to the buffer. 161 | * The \p size parameter should not exceed the last value returned by usbComTxAvailable(). */ 162 | void usbComTxSend(const uint8 XDATA * buffer, uint8 size); 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /libraries/xpage/xpage.lst: -------------------------------------------------------------------------------- 1 | 1 ;-------------------------------------------------------- 2 | 2 ; File Created by SDCC : free open source ANSI-C Compiler 3 | 3 ; Version 3.0.0 #6037 (Oct 31 2010) (MINGW32) 4 | 4 ; This file was generated Thu Dec 09 12:45:16 2010 5 | 5 ;-------------------------------------------------------- 6 | 6 .module xpage 7 | 7 .optsdcc -mmcs51 --model-medium 8 | 8 9 | 9 ;-------------------------------------------------------- 10 | 10 ; Public variables in this module 11 | 11 ;-------------------------------------------------------- 12 | 12 .globl __XPAGE 13 | 13 ;-------------------------------------------------------- 14 | 14 ; special function registers 15 | 15 ;-------------------------------------------------------- 16 | 16 .area RSEG (ABS,DATA) 17 | 0000 17 .org 0x0000 18 | 0093 18 __XPAGE = 0x0093 19 | 19 ;-------------------------------------------------------- 20 | 20 ; special function bits 21 | 21 ;-------------------------------------------------------- 22 | 22 .area RSEG (ABS,DATA) 23 | 0000 23 .org 0x0000 24 | 24 ;-------------------------------------------------------- 25 | 25 ; overlayable register banks 26 | 26 ;-------------------------------------------------------- 27 | 27 .area REG_BANK_0 (REL,OVR,DATA) 28 | 0000 28 .ds 8 29 | 29 ;-------------------------------------------------------- 30 | 30 ; internal ram data 31 | 31 ;-------------------------------------------------------- 32 | 32 .area DSEG (DATA) 33 | 33 ;-------------------------------------------------------- 34 | 34 ; overlayable items in internal ram 35 | 35 ;-------------------------------------------------------- 36 | 36 .area OSEG (OVR,DATA) 37 | 37 ;-------------------------------------------------------- 38 | 38 ; indirectly addressable internal ram data 39 | 39 ;-------------------------------------------------------- 40 | 40 .area ISEG (DATA) 41 | 41 ;-------------------------------------------------------- 42 | 42 ; absolute internal ram data 43 | 43 ;-------------------------------------------------------- 44 | 44 .area IABS (ABS,DATA) 45 | 45 .area IABS (ABS,DATA) 46 | 46 ;-------------------------------------------------------- 47 | 47 ; bit data 48 | 48 ;-------------------------------------------------------- 49 | 49 .area BSEG (BIT) 50 | 50 ;-------------------------------------------------------- 51 | 51 ; paged external ram data 52 | 52 ;-------------------------------------------------------- 53 | 53 .area PSEG (PAG,XDATA) 54 | 54 ;-------------------------------------------------------- 55 | 55 ; external ram data 56 | 56 ;-------------------------------------------------------- 57 | 57 .area XSEG (XDATA) 58 | 58 ;-------------------------------------------------------- 59 | 59 ; absolute external ram data 60 | 60 ;-------------------------------------------------------- 61 | 61 .area XABS (ABS,XDATA) 62 | 62 ;-------------------------------------------------------- 63 | 63 ; external initialized ram data 64 | 64 ;-------------------------------------------------------- 65 | 65 .area XISEG (XDATA) 66 | 66 .area HOME (CODE) 67 | 67 .area GSINIT0 (CODE) 68 | 68 .area GSINIT1 (CODE) 69 | 69 .area GSINIT2 (CODE) 70 | 70 .area GSINIT3 (CODE) 71 | 71 .area GSINIT4 (CODE) 72 | 72 .area GSINIT5 (CODE) 73 | 73 .area GSINIT (CODE) 74 | 74 .area GSFINAL (CODE) 75 | 75 .area CSEG (CODE) 76 | 76 ;-------------------------------------------------------- 77 | 77 ; global & static initialisations 78 | 78 ;-------------------------------------------------------- 79 | 79 .area HOME (CODE) 80 | 80 .area GSINIT (CODE) 81 | 81 .area GSFINAL (CODE) 82 | 82 .area GSINIT (CODE) 83 | 83 ;-------------------------------------------------------- 84 | 84 ; Home 85 | 85 ;-------------------------------------------------------- 86 | 86 .area HOME (CODE) 87 | 87 .area HOME (CODE) 88 | 88 ;-------------------------------------------------------- 89 | 89 ; code 90 | 90 ;-------------------------------------------------------- 91 | 91 .area CSEG (CODE) 92 | 92 .area CSEG (CODE) 93 | 93 .area CONST (CODE) 94 | 94 .area XINIT (CODE) 95 | 95 .area CABS (ABS,CODE) 96 | -------------------------------------------------------------------------------- /libraries/include/adc.h: -------------------------------------------------------------------------------- 1 | /*! \file adc.h 2 | * The adc.lib library provides functions for using the CC2511's 3 | * Analog-to-Digital Converter (ADC). The ADC can measure several 4 | * different things, including voltages on any of the six Port 0 pins, the 5 | * voltage on the VDD line (the 3V3 pin on the Wixel), and the temperature. 6 | * 7 | * The ADC has 14 channels: 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | *
CC2511 ADC Channels
Channel NumberNameAppropriate Function
0AIN0 (P0_0)adcRead()
1AIN1 (P0_1)adcRead()
2AIN2 (P0_2)adcRead()
3AIN3 (P0_3)adcRead()
4AIN4 (P0_4)adcRead()
5AIN5 (P0_5)adcRead()
8AIN0 - AIN1adcReadDifferential()
9AIN2 - AIN3adcReadDifferential()
10AIN4 - AIN5adcReadDifferential()
11AIN6 - AIN7adcReadDifferential()
12GND
13Internal 1.25 V ReferenceadcRead()
14Temperature SensoradcRead()
15VDD/3
26 | * 27 | * \section channelparam The channel parameter 28 | * 29 | * Most functions in this library require a channel parameter to 30 | * specify which channel to use. The value of this parameter should 31 | * be one of the channel numbers in the table above. 32 | * 33 | * You can also use the bitwise OR operator (|) to specify advanced options 34 | * in the channel parameter: 35 | * - By default, VDD is used as a reference but you can use the internal 36 | * 1.25 V source as a reference by specifying #ADC_REFERENCE_INTERNAL 37 | * in the channel parameter. 38 | * - By default, the maximum ADC resolution (12 bits) is used, but you can 39 | * use a different resolution by specifying #ADC_BITS_10, #ADC_BITS_9, or 40 | * #ADC_BITS_7 in the channel parameter. 41 | * 42 | */ 43 | 44 | #ifndef _ADC_H 45 | #define _ADC_H 46 | 47 | /*! Specifies that the internal 1.25 voltage reference should be used. 48 | * This means that a value of 2047 corresponds to 1.25 V instead of 49 | * 3.3 V. */ 50 | #define ADC_REFERENCE_INTERNAL 0b10000000 51 | 52 | /*! Specifies that the VDD line should be used as a voltage reference. 53 | * This means that a value of 2047 corresponds to VDD (usually 3.3 V). 54 | * This is the default setting. */ 55 | #define ADC_REFERENCE_VDD 0 56 | 57 | /*! Specifies that the decimation rate should be 64, which gives 58 | * 7 bits of resolution. With this setting, each conversion takes 20 59 | * microseconds. 60 | */ 61 | #define ADC_BITS_7 0b00110000 62 | 63 | /*! Specifies that the decimation rate should be 128, which gives 64 | * 9 bits of resolution. With this setting, each conversion takes 36 65 | * microseconds. 66 | */ 67 | #define ADC_BITS_9 0b00100000 68 | 69 | /*! Specifies that the decimation rate should be 256, which gives 70 | * 10 bits of resolution. With this setting, each conversion takes 68 71 | * microseconds. 72 | */ 73 | #define ADC_BITS_10 0b00010000 74 | 75 | /*! Specifies that the decimation rate should be 512, which gives 76 | * 12 bits of resolution. With this setting, each conversion takes 132 77 | * microseconds. This is the default setting. 78 | */ 79 | #define ADC_BITS_12 0 80 | 81 | /*! Reads the voltage on the specified channel. 82 | * 83 | * \param channel The number of the channel to measure (0-6 or 13-15). 84 | * This parameter can also contain advanced options (see above). 85 | * 86 | * \return A number between 0 and 2047, where 0 represents a voltage 87 | * of 0 V and 2047 represents a voltage equal to the selected 88 | * voltage reference (usually 3.3 V). 89 | * 90 | * Example: 91 | * \code 92 | uint16 result1, result2; 93 | result1 = adcRead(3); // Measures voltage on P0_3. 94 | result2 = adcRead(4 | ADC_REFERENCE_INTERNAL | ADC_BITS_7); 95 | * \endcode 96 | * 97 | * This function returns an unsigned number so it is not appropriate for 98 | * differential channels. See adcReadDifferential(). 99 | * 100 | */ 101 | uint16 adcRead(uint8 channel); 102 | 103 | /*! Reads the voltage difference on the specified differential channel. 104 | * 105 | * \param channel The number of the differential channel to measure (8-11). 106 | * This parameter can also contain advanced options (see above). 107 | * 108 | * \return A number between -2048 and 2047. A value of 2047 means that 109 | * the voltage difference was equal to the selected voltage reference. 110 | * A value of -2048 means that the voltage difference was equal to 111 | * the negation of the selected voltage reference. 112 | * A value of 0 means that the voltage difference was zero. 113 | * 114 | * Example: 115 | * \code 116 | int16 diff1, diff2; 117 | diff1 = adcReadDifferential(8); // Measures (voltage of P0_0) - (voltage of P0_1). 118 | diff2 = adcReadDifferential(9 | ADC_REFERENCE_INTERNAL | ADC_BITS_7); 119 | * \endcode 120 | */ 121 | int16 adcReadDifferential(uint8 channel); 122 | 123 | /*! Reads the voltage of the VDD (3V3) line using the internal voltage 124 | * reference and returns the voltage of VDD in units of millivolts (mV). */ 125 | uint16 adcReadVddMillivolts(); 126 | 127 | /*! Sets the calibration parameter that is used by adcConvertToMillivolts(). 128 | * \param vddMillivolts The voltage of the VDD line in units of millivolts. 129 | * 130 | * If your VDD is going to drop below 3.3 V, and you want to measure a 131 | * voltage in units of millivolts (as opposed to the raw ADC units) 132 | * you should run the following code regularly: 133 | * 134 | \code 135 | adcSetMillivoltCalibration(adcReadVddMillivolts()); 136 | \endcode 137 | */ 138 | void adcSetMillivoltCalibration(uint16 vddMillivolts); 139 | 140 | /*! Converts an ADC result to millivolts. 141 | * 142 | * \param adcResult An ADC result between -2048 and 2047 that was 143 | * measured using VDD as a reference. You can obtain such a 144 | * measurement by calling adcRead() or adcReadDifferential(). 145 | * 146 | * \return The voltage in units of millivolts. 147 | * 148 | * By default, this function assumes that your VDD is at 3300 mV. 149 | * If you expect your VDD to go above or below that, or you want 150 | * more accurate results, you should use adcSetMillivoltCalibration(). 151 | * 152 | * This function only applies to AD conversions where VDD was used as 153 | * a reference. If you used the internal 1.25 V reference instead, you 154 | * can convert your result to millivolts by multiplying it by 155 | * 1250 and then dividing it by 2047. */ 156 | int16 adcConvertToMillivolts(int16 adcResult); 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /libraries/src/i2c/i2c.c: -------------------------------------------------------------------------------- 1 | /* i2c.c: A basic software implementation of a master node for I2C communication 2 | * (the CC2511 does not have a hardware I2C module). This library does not 3 | * support multi-master I2C buses. 4 | */ 5 | 6 | /* Dependencies ***************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* Global Constants & Variables ***********************************************/ 15 | 16 | uint8 DATA i2cPinScl = 10; // P1_0 17 | uint8 DATA i2cPinSda = 11; // P1_1 18 | 19 | static uint16 XDATA halfPeriodUs = 5; // freq = 100 kHz 20 | static uint16 XDATA timeout = 10; 21 | static BIT started = 0; 22 | 23 | /* i2cTimeoutOccurred is the publicly readable error flag. It must be manually 24 | * cleared. 25 | * We have an internal timeout flag too so that e.g. i2cReadByte can abort if 26 | * i2cReadBit times out, but we can clear the internal flag at the beginning of 27 | * i2cReadByte so an earlier timeout doesn't affect a later call. 28 | */ 29 | BIT i2cTimeoutOccurred = 0; 30 | static BIT internalTimeoutOccurred = 0; 31 | 32 | 33 | /* Functions ******************************************************************/ 34 | 35 | void i2cSetFrequency(uint16 freqKHz) 36 | { 37 | // delayMicroseconds takes a uint8, so halfPeriodUs cannot be more than 255 38 | if (freqKHz < 2) 39 | { 40 | freqKHz = 2; 41 | } 42 | 43 | // force halfPeriodUs to round up so we don't use a higher frequency than what was chosen 44 | // TODO: implement a timing function with better resolution than delayMicroseconds to allow finer-grained frequency control? 45 | halfPeriodUs = (500 + freqKHz - 1) / freqKHz; 46 | } 47 | 48 | void i2cSetTimeout(uint16 timeoutMs) 49 | { 50 | timeout = timeoutMs; 51 | } 52 | 53 | BIT i2cReadScl(void) 54 | { 55 | setDigitalInput(i2cPinScl, HIGH_IMPEDANCE); 56 | return isPinHigh(i2cPinScl); 57 | } 58 | 59 | BIT i2cReadSda(void) 60 | { 61 | setDigitalInput(i2cPinSda, HIGH_IMPEDANCE); 62 | return isPinHigh(i2cPinSda); 63 | } 64 | 65 | void i2cClearScl(void) 66 | { 67 | setDigitalOutput(i2cPinScl, LOW); 68 | } 69 | 70 | void i2cClearSda(void) 71 | { 72 | setDigitalOutput(i2cPinSda, LOW); 73 | } 74 | 75 | void i2cWaitForHighScl(uint16 timeoutMs) 76 | { 77 | uint32 time = getMs(); 78 | while (i2cReadScl() == 0) 79 | { 80 | if (getMs() - time > timeoutMs) 81 | { 82 | internalTimeoutOccurred = 1; 83 | i2cTimeoutOccurred = 1; 84 | started = 0; 85 | return; 86 | } 87 | } 88 | } 89 | 90 | /* Generate an I2C STOP condition (P): 91 | * SDA goes high while SCL is high 92 | */ 93 | void i2cStop(void) 94 | { 95 | i2cClearSda(); // drive SDA low while SCL is low 96 | delayMicroseconds(halfPeriodUs); 97 | 98 | // handle clock stretching 99 | i2cWaitForHighScl(timeout); 100 | if (internalTimeoutOccurred) return; 101 | 102 | // SCL is now high 103 | i2cReadSda(); // let SDA line go high while SCL is high 104 | delayMicroseconds(halfPeriodUs); 105 | started = 0; 106 | } 107 | 108 | /* Generate an I2C START or repeated START condition (S): 109 | * SDA goes low while SCL is high 110 | */ 111 | void i2cStart(void) 112 | { 113 | // if started == 1, do a repeated start 114 | if (started) 115 | { 116 | i2cReadSda(); // let SDA line go high while SCL is low 117 | delayMicroseconds(halfPeriodUs); 118 | } 119 | 120 | // handle clock stretching 121 | i2cWaitForHighScl(timeout); 122 | if (internalTimeoutOccurred) return; 123 | 124 | // SCL is now high 125 | i2cClearSda(); // drive SDA low while SCL is high 126 | delayMicroseconds(halfPeriodUs); 127 | i2cClearScl(); // drive SCL low 128 | started = 1; 129 | } 130 | 131 | /* Write a bit to the I2C bus 132 | * It is assumed that SCL is low when this function starts. 133 | * SDA is set to the appropriate bit value while SCL is low, there is a 134 | * delay for half of the clock period while SDA stablizes, then SCL 135 | * is allowed to go high for the second half of the clock period, which 136 | * indicates the on SDA is valid. This function drives SCL low again 137 | * before it returns. 138 | */ 139 | void i2cWriteBit(BIT b) 140 | { 141 | if (b) 142 | { 143 | i2cReadSda(); // let SDA go high 144 | } 145 | else 146 | { 147 | i2cClearSda(); // drive SDA low 148 | } 149 | delayMicroseconds(halfPeriodUs); 150 | 151 | // handle clock stretching 152 | i2cWaitForHighScl(timeout); 153 | if (internalTimeoutOccurred) return; 154 | 155 | // SCL is now high, data is valid 156 | delayMicroseconds(halfPeriodUs); 157 | i2cClearScl(); // drive SCL low 158 | } 159 | 160 | /* Read a bit to the I2C bus 161 | * It is assumed that SCL is low when this function starts. 162 | * The master tristates SDA so the slave transmitter can control the state 163 | * and delays for half of the clock period (or longer if the slave is holding 164 | * SCL low). It then lets SCL go high, records the state of the SDA line, 165 | * and delays for the second half of the clock period. This function drives SCL 166 | * low again before it returns. Return value is not meaningful if timeout 167 | * occurs. 168 | */ 169 | BIT i2cReadBit(void) 170 | { 171 | BIT b; 172 | 173 | i2cReadSda(); // let slave transmitter control state of SDA line 174 | delayMicroseconds(halfPeriodUs); 175 | 176 | // handle clock stretching 177 | i2cWaitForHighScl(timeout); 178 | if (internalTimeoutOccurred) return 0; 179 | 180 | // SCL is now high, data is valid 181 | b = i2cReadSda(); // store state of SDA line now that SCL is high 182 | delayMicroseconds(halfPeriodUs); 183 | i2cClearScl(); // drive SCL low 184 | return b; 185 | } 186 | 187 | /* Write a byte to I2C bus. Return 0 if ack by the slave, 1 if nack. 188 | * The return value is not meaningful if a timeout occurs. 189 | */ 190 | BIT i2cWriteByte(uint8 byte) 191 | { 192 | uint8 i; 193 | BIT nack; 194 | 195 | internalTimeoutOccurred = 0; 196 | 197 | for (i = 0; i < 8; i++) 198 | { 199 | i2cWriteBit(byte & 0x80); 200 | if (internalTimeoutOccurred) return 0; 201 | byte <<= 1; 202 | } 203 | nack = i2cReadBit(); 204 | if (internalTimeoutOccurred) return 0; 205 | 206 | if (nack) 207 | { 208 | i2cStop(); 209 | if (internalTimeoutOccurred) return 0; 210 | } 211 | return nack; 212 | } 213 | 214 | /* Read a byte from I2C bus. 215 | * The return value is not meaningful if a timeout occurs. 216 | */ 217 | uint8 i2cReadByte(BIT nack) 218 | { 219 | uint16 byte = 0; 220 | uint8 i; 221 | BIT b; 222 | 223 | internalTimeoutOccurred = 0; 224 | 225 | for (i = 0; i < 8; i++) 226 | { 227 | b = i2cReadBit(); 228 | if (internalTimeoutOccurred) return 0; 229 | byte = (byte << 1) | b; 230 | } 231 | 232 | i2cWriteBit(nack); 233 | if (internalTimeoutOccurred) return 0; 234 | 235 | return byte; 236 | } 237 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This is Makefile defines how to compile all of the libraries and applications 2 | # in the SDK. 3 | # See README.txt for instructions on how to get started using this SDK. 4 | # type `make` or `make apps` to make all of the apps in the apps folder 5 | # type `make APPNAME` to make a specific app 6 | # type `make libs` to make all the libraries 7 | 8 | .DEFAULT_GOAL := apps 9 | 10 | #### Programs used by this Makefile ############################################ 11 | CC := sdcc# C compiler: creates object files (.rel) from C files (.c) 12 | AS := sdas8051# Assembler: creates object files (.rel) from assembly files (.s) 13 | AR := sdcclib# Librarian: creates .lib 14 | LD := sdld# Linker: creates .hex files from .rel/.lib files) 15 | PACKIHX := packihx# makes .hex files smaller 16 | MV := move# moves files 17 | CP := cp# copies files 18 | CAT := cat# outputs files 19 | ECHO := echo# outputs some text to the standard output 20 | GREP := grep# outputs lines from a file that match a given pattern 21 | SED := sed# edits files 22 | WIXELCMD := wixelcmd# loads programs on the Wixel (command-line utility) 23 | WIXELCONFIG := wixelconfig # Wixel Configuration Utility (GUI) 24 | 25 | #### Include directories ####################################################### 26 | INCDIRS += libraries/include 27 | I_FLAGS = $(patsubst %,-I%,$(INCDIRS)) 28 | 29 | #### Compilation options ####################################################### 30 | 31 | # Generate dependency information 32 | C_FLAGS += -Wp,-MD,$(@:%.rel=%.d),-MT,$@,-MP 33 | 34 | # Disable warning 110: conditional flow changed by optimizer 35 | WARNING := --disable-warning 110 36 | C_FLAGS += $(WARNINGS) 37 | 38 | # Add the include directories 39 | C_FLAGS += $(I_FLAGS) 40 | 41 | # Disable pagination in .lst file 42 | C_FLAGS += -Wa,-p 43 | AS_FLAGS += -p 44 | 45 | # Put the output in the right place. 46 | PPC_FLAGS += -Wp,-o,$@ 47 | 48 | MODEL = --model-medium 49 | C_FLAGS += $(MODEL) 50 | LD_FLAGS += $(MODEL) 51 | 52 | # Generate debugging information (.cdb files). 53 | C_FLAGS += --debug 54 | LD_FLAGS += --debug 55 | 56 | #### Code area options ######################################################### 57 | # --code-loc corresponds to the "-b HOME =" linker argument 58 | # --code-size corresponds to the "-w" argument to the linker 59 | 60 | # CODE_AREA_FULL: Uses all 32k on the chip. 61 | CODE_AREA_FULL = --code-loc 0x0000 --code-size 0x8000 62 | 63 | # CODE_AREA_APP: Creates an application that can be loaded with the bootloader, 64 | # using only kilobytes 1-29 inclusive. 65 | CODE_AREA_APP = --code-loc 0x0400 --code-size 0x7400 66 | 67 | # The default code area is CODE_AREA_APP. 68 | CODE_AREA := $(CODE_AREA_APP) 69 | LD_FLAGS += $(CODE_AREA) 70 | 71 | #### Linking options ########################################################### 72 | 73 | # The size of internal ram. ("-a" argument to the linker) 74 | LD_FLAGS += --iram-size 0x0100 75 | 76 | # XRAM location. ("-b XSEG =" and "-b PSEG =" arguments to linker) 77 | LD_FLAGS += --xram-loc 0xF000 78 | 79 | # XRAM size. ("-v" argument to linker) 80 | LD_FLAGS += --xram-size 0xF00 81 | 82 | # Put the output in the right place. 83 | LD_FLAGS += -o $(@:%.hex=%.ihx) 84 | 85 | #### MODULES ################################################################### 86 | TARGETS := 87 | RELs := 88 | LIBs := 89 | HEXs := 90 | 91 | include libraries/libs.mk 92 | include apps.mk 93 | 94 | #### FILES TYPES ############################################################### 95 | # .c : This is a file that contains source code in the C language. 96 | # .h : Header file in the C language (part of the source code). 97 | # .s : Assembly language source code. 98 | # 99 | # .rel : This is an Object file, the result of compiling a .s or .c file. 100 | # .lib : This is a library (a collection of several object files). 101 | # .hex : This is a complete program that can be loaded onto a Wixel. 102 | # 103 | # The lists of all .rel/lib/hex files compiled by this Makefile are in the 104 | # following variables: $(RELs) $(LIBs) $(HEXs) 105 | 106 | # These files are generated when compiling a .c file. 107 | Ds := $(RELs:%.rel=%.d) # .d : dependency information 108 | CDBs := $(RELs:%.rel=%.cdb) # .cdb : debugging information 109 | ADBs := $(RELs:%.rel=%.adb) # .adb : debugging information 110 | ASMs := $(RELs:%.rel=%.asm) # .asm : assembly generated by compiler 111 | 112 | # These files are generated when compiling a .s or .c file. 113 | SYMs := $(RELs:%.rel=%.sym) # .sym : symbol table 114 | LSTs := $(RELs:%.rel=%.lst) # .lst : listing without absolute addresses 115 | RSTs := $(RELs:%.rel=%.rst) # .rst : listing with absolute addresses 116 | 117 | # These files are generated when linking: 118 | MEMs := $(HEXs:%.hex=%.mem) # .mem : summary of memory usage 119 | MAPs := $(HEXs:%.hex=%.map) # .map : list of all addresses and memory sections 120 | LKs := $(HEXs:%.hex=%.lk) # .lk : args used by the linker 121 | LNKs := $(HEXs:%.hex=%.lnk) # .lnk : args used by the linker (prior to SDCC 3.1.0) 122 | CDBs := $(HEXs:%.hex=%.cdb) # .cdb : debugging information 123 | OMFs := $(HEXs:%.hex=%) $(HEXs:%.hex=%.omf) # .omf : had no extension prior to SDCC 3.1.0 124 | 125 | # These files can be generated from a .hex and .cdb file. 126 | WXLs := $(HEXs:%.hex=%.wxl) # .wxl : Wixel application 127 | WXLs += $(HEXs:%.hex=%.wxl.tmp) 128 | 129 | #### TARGETS ################################################################### 130 | TARGETS += $(RELs) $(HEXs) $(LIBs) 131 | 132 | all: $(TARGETS) apps 133 | 134 | .PHONY: clean 135 | clean: 136 | -@rm -fv $(TARGETS) 137 | -@rm -fv $(CLEAN) 138 | -@rm -fv $(Ds) 139 | -@rm -fv $(SYMs) 140 | -@rm -fv $(CDBs) 141 | -@rm -fv $(MEMs) 142 | -@rm -fv $(RSTs) 143 | -@rm -fv $(MAPs) 144 | -@rm -fv $(LSTs) 145 | -@rm -fv $(LKs) 146 | -@rm -fv $(LNKs) 147 | -@rm -fv $(BINs) 148 | -@rm -fv $(ASMs) 149 | -@rm -fv $(OMFs) 150 | -@rm -fv $(ADBs) 151 | -@rm -fv $(CDBs) 152 | -@rm -fv $(WXLs) 153 | 154 | #### COMPLETE COMMANDS ######################################################### 155 | 156 | ifdef VERBOSE 157 | COMPILE_COMMAND = $(CC) -c $< $(C_FLAGS) -o $@ 158 | ASSEMBLE_COMMAND = $(AS) -glos $(AS_FLAGS) $< 159 | ARCHIVE_COMMAND = $(AR) $@ $^ 160 | LINK_COMMAND = $(CC) $(LD_FLAGS) libraries/xpage/xpage.rel $^ 161 | else 162 | V=@ 163 | COMPILE_COMMAND = @echo Compiling $@ && $(CC) -c $< $(C_FLAGS) -o $@ 164 | ASSEMBLE_COMMAND = @echo Assembling $@ && $(AS) -glos $(AS_FLAGS) $< 165 | ARCHIVE_COMMAND = @echo Creating $@ && $(AR) $@ $^ 166 | LINK_COMMAND = @echo Linking $@ && $(CC) $(LD_FLAGS) libraries/xpage/xpage.rel $^ 167 | endif 168 | 169 | #### IMPLICIT RULES ############################################################ 170 | 171 | %.rel: %.c 172 | $(COMPILE_COMMAND) 173 | 174 | %.rel: %.s 175 | $(ASSEMBLE_COMMAND) 176 | 177 | %.lib: 178 | $(V)rm -f $@ 179 | $(ARCHIVE_COMMAND) 180 | 181 | #%.hex: %.rel 182 | # $(LINK_COMMAND) 183 | # @mv -f $(@:%.hex=%.ihx) $@ 184 | 185 | %.wxl: %.hex 186 | @echo Packaging $@ 187 | $(V)$(ECHO) Pololu Wixel Application - www.pololu.com> $@.tmp 188 | $(V)$(ECHO) 1.0>> $@.tmp 189 | $(V)$(ECHO) ====== license>> $@.tmp 190 | $(V)$(CAT) LICENSE.txt >> $@.tmp 191 | $(V)$(ECHO) ====== cdb>> $@.tmp 192 | $(V)$(GREP) param $(<:%.hex=%.cdb) >> $@.tmp || echo "(This app has no params.)" 193 | $(V)$(ECHO) ====== hex>> $@.tmp 194 | $(V)$(PACKIHX) $< >> $@.tmp 195 | $(V)$(SED) -f libraries/dos_newlines.sed $@.tmp > $@ 196 | $(V)$(RM) $@.tmp 197 | 198 | # Include all the dependency files generated during compilation so that Make 199 | # knows which .rel files to recompile when a .h file changes. 200 | -include $(Ds) 201 | -------------------------------------------------------------------------------- /libraries/include/radio_link.h: -------------------------------------------------------------------------------- 1 | /*! \file radio_link.h 2 | * The radio_link.lib library provides reliable, ordered delivery 3 | * and reception of a series of data packets between two Wixels on the same frequency. 4 | * This is the library that takes 5 | * care of Ping/ACK/NAK packets and handles the details of timing. 6 | * This library defines radio packet memory buffers and controls access to those 7 | * buffers. 8 | * 9 | * This library does not work if there are more than two Wixels broadcasting 10 | * on the same channel. 11 | * For wireless communication between more than two Wixels, you can use 12 | * radio_queue.lib (see radio_queue.h). 13 | * 14 | * Similarly, this library also restricts the Wixels to only having one logical data pipe. 15 | * If you want to send some extra data that doesn't get NAKed, or gets NAKed at 16 | * different times then the regular data, you would need to replace this library with 17 | * something more complicated that keeps track of different streams and schedules them. 18 | * 19 | * This library depends on radio_mac.lib, which uses an interrupt. 20 | * For this library to work, you must write 21 | * include 22 | * in the source file that contains your main() function. 23 | */ 24 | 25 | #ifndef _RADIO_LINK 26 | #define _RADIO_LINK 27 | 28 | #include 29 | #include 30 | 31 | /*! Each packet can contain at most 18 bytes of payload. 32 | * This limit is imposed by the radio_link.lib library, 33 | * not the CC2511. */ 34 | #define RADIO_LINK_PAYLOAD_SIZE 18 35 | 36 | /*! Each packet has a "Payload Type" attached to it, 37 | * which is a number between 0 and #RADIO_LINK_MAX_PAYLOAD_TYPE. 38 | * The meanings of the different payload types can be defined by 39 | * higher-level code. */ 40 | #define RADIO_LINK_MAX_PAYLOAD_TYPE 15 41 | 42 | /*! Defines the frequency to use. Valid values are from 43 | * 0 to 255. To avoid interference, the channel numbers of 44 | * different Wixel pairs operating in the should be at least 45 | * 2 apart. (This is a Wixel App parameter; the user can set 46 | * it using the Wixel Configuration Utility.) */ 47 | extern int32 CODE param_radio_channel; 48 | 49 | /*! This bit allows the higher-level code to detect when a reset packet 50 | * is received. It is set to 1 in an interrupt by the radio_link.lib library 51 | * whenever a reset packet is received. The higher-level code should set 52 | * it to zero when it uses this information. 53 | * 54 | * A reset packet will be received whenever the other Wixel is reset for 55 | * any reason. Multiple reset packets can also be received in quick 56 | * succession if the other device does not receive the acknowledgment 57 | * packet sent by this device (every radio packet has a chance of being 58 | * lost). This situation is indistinguishable from the situation where 59 | * the other party is actually getting reset several times in quick 60 | * succession. 61 | * 62 | * If the higher-level code responds to this bit by sending an initialization 63 | * packet to the other device, then it should clear #radioLinkResetPacketReceived 64 | * BEFORE queueing the packet to be sent. Otherwise, the following 65 | * sequence of events could occur: 66 | * -# Main Loop: This device detects a reset packet (#radioLinkResetPacketReceived==1). 67 | * -# Main Loop: This device queues initialization packet to be sent. 68 | * -# ISR: This device sends an initialization packet. 69 | * -# ISR: This device receives a reset packet because other device got reset. 70 | * -# This device clears the #radioLinkResetPacketReceived. 71 | * 72 | * By clearing the bit first, you guarantee that an initialization packet will 73 | * be sent AFTER the final reset packet is received. 74 | * 75 | * Example use: 76 | \code 77 | if (radioLinkResetPacketReceived && radioLinkTxAvailable()) 78 | { 79 | uint8 XDATA * packet; 80 | 81 | // A reset packet from the other party was received, so send 82 | // a packet to initialize the connection. 83 | 84 | // Clear the flag. This must be done BEFORE queueing the packet 85 | // to be sent, as discussed in radio_link.h 86 | radioLinkResetPacketReceived = 0; 87 | 88 | packet = radioLinkTxAvailable(); 89 | packet[0] = INIT_PACKET_LENGTH; // defined by higher-level code 90 | packet[1] = INIT_PACKET_PAYLOAD; // defined by higher-level code 91 | radioLinkTxSendPacket(INIT_PACKET_PAYLOAD_TYPE); 92 | } 93 | \endcode 94 | */ 95 | extern volatile BIT radioLinkResetPacketReceived; 96 | 97 | /*! Initializes the radio_link.lib library and the lower-level 98 | * libraries that it depends on. This must be called before 99 | * any other functions in the library. */ 100 | void radioLinkInit(void); 101 | 102 | /*! \return The number of radio TX packet buffers that are currently free 103 | * (available to hold data). */ 104 | uint8 radioLinkTxAvailable(void); 105 | 106 | /*! \return The number of radio TX packet buffers that are currently busy 107 | * (holding a data packet that has not been successfully sent yet). */ 108 | uint8 radioLinkTxQueued(void); 109 | 110 | /*! \return A pointer to the current TX packet, or 0 if no packet is available. 111 | * 112 | * To populate this packet, you should 113 | * write the length of the payload data (which must not exceed 114 | * #RADIO_LINK_PAYLOAD_SIZE) to offset 0, and write the data starting at 115 | * offset 1. After you have put this data in the packet, call 116 | * radioLinkTxSendPacket() to actually queue the packet up to be sent on 117 | * the radio. 118 | * Example usage: 119 | \code 120 | uint8 XDATA * packet = radioLinkTxCurrentPacket(); 121 | if (packet != 0) 122 | { 123 | packet[0] = 3; // payload length. Must not exceed RADIO_LINK_PAYLOAD_SIZE. 124 | packet[1] = 'a'; 125 | packet[2] = 'b'; 126 | packet[3] = 'c'; 127 | radioLinkTxSendPacket(0); 128 | } 129 | \endcode 130 | * 131 | * This function has no side effects. 132 | */ 133 | uint8 XDATA * radioLinkTxCurrentPacket(void); 134 | 135 | /*! Sends the current TX packet. See the documentation of 136 | * radioLinkTxCurrentPacket() for details. 137 | * 138 | * \param payloadType A number between 0 and RADIO_LINK_MAX_PACKET_TYPE that 139 | * will be attached to the packet. This can be used to specify what type of 140 | * data the packet contains. 141 | * */ 142 | void radioLinkTxSendPacket(uint8 payloadType); 143 | 144 | /*! \return A pointer to the current RX packet. 145 | * This is the earliest packet received from the other Wixel 146 | * which has not yet been processed yet by higher-level code. 147 | * Returns 0 if there is no RX packet available. 148 | * 149 | * The RX packet has the same format as the TX packet: the length of the 150 | * payload is at offset 0 and the data starts at offset 1. 151 | * 152 | * When you are done reading the packet you should call 153 | * radioLinkRxDoneWithPacket() to advance to the next packet. 154 | */ 155 | uint8 XDATA * radioLinkRxCurrentPacket(void); // returns 0 if no packet is available. 156 | 157 | /*! \return The payload type of the current RX packet. This number was the 158 | * argument to radioLinkTxSendPacket() on the other Wixel. 159 | * 160 | * This should only be called if radioLinkRxCurrentPacket() recently returned 161 | * a non-zero pointer. */ 162 | uint8 radioLinkRxCurrentPayloadType(void); 163 | 164 | /*! Frees the current RX packet so that you can advance to processing 165 | * the next one. See the radioLinkRxCurrentPacket() documentation for details. */ 166 | void radioLinkRxDoneWithPacket(void); 167 | 168 | /*! \return 1 if a connection to another Wixel has been established. 169 | * 170 | * Currently the radio_link library does not detect disconnection, so this value 171 | * will never change from 1 to 0. */ 172 | BIT radioLinkConnected(void); 173 | 174 | /*! The library will set this bit to 1 whenever it receives a packet that 175 | * has payload data in it or sends a packet. 176 | * Higher-level code may check this bit and clear it. */ 177 | extern volatile BIT radioLinkActivityOccurred; 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /libraries/src/spi_master/core/spi_master.c: -------------------------------------------------------------------------------- 1 | /** \file spi_master.c 2 | * This is the main source file for spi_master.c. See spi_master.h for 3 | * information on how to use this library. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #if defined(__CDT_PARSER__) 10 | #define SPI0 11 | #endif 12 | 13 | #if defined(SPI0) 14 | #include 15 | #define INTERRUPT_PRIORITY_GROUP 2 16 | #define ISR_URX() ISR(URX0, 0) 17 | #define URXNIF URX0IF 18 | #define URXNIE URX0IE 19 | #define UNGCR U0GCR 20 | #define UNBAUD U0BAUD 21 | #define UNDBUF U0DBUF 22 | #define spiNMasterInit spi0MasterInit 23 | #define spiNMasterSetFrequency spi0MasterSetFrequency 24 | #define spiNMasterSetClockPolarity spi0MasterSetClockPolarity 25 | #define spiNMasterSetClockPhase spi0MasterSetClockPhase 26 | #define spiNMasterSetBitOrder spi0MasterSetBitOrder 27 | #define spiNMasterBusy spi0MasterBusy 28 | #define spiNMasterBytesLeft spi0MasterBytesLeft 29 | #define spiNMasterTransfer spi0MasterTransfer 30 | #define spiNMasterSendByte spi0MasterSendByte 31 | #define spiNMasterReceiveByte spi0MasterReceiveByte 32 | 33 | #elif defined(SPI1) 34 | #include 35 | #define INTERRUPT_PRIORITY_GROUP 3 36 | #define ISR_URX() ISR(URX1, 0) 37 | #define URXNIF URX1IF 38 | #define URXNIE URX1IE 39 | #define UNGCR U1GCR 40 | #define UNBAUD U1BAUD 41 | #define UNDBUF U1DBUF 42 | #define spiNMasterInit spi1MasterInit 43 | #define spiNMasterSetFrequency spi1MasterSetFrequency 44 | #define spiNMasterSetClockPolarity spi1MasterSetClockPolarity 45 | #define spiNMasterSetClockPhase spi1MasterSetClockPhase 46 | #define spiNMasterSetBitOrder spi1MasterSetBitOrder 47 | #define spiNMasterBusy spi1MasterBusy 48 | #define spiNMasterBytesLeft spi1MasterBytesLeft 49 | #define spiNMasterTransfer spi1MasterTransfer 50 | #define spiNMasterSendByte spi1MasterSendByte 51 | #define spiNMasterReceiveByte spi1MasterReceiveByte 52 | #endif 53 | 54 | // txPointer points to the last byte that was written to SPI. 55 | static volatile const uint8 XDATA * DATA txPointer = 0; 56 | 57 | // rxPointer points to the location to store the next byte received from SPI. 58 | static volatile uint8 XDATA * DATA rxPointer = 0; 59 | 60 | // bytesLeft is the number of bytes we still need to send to/receive from SPI. 61 | static volatile uint16 DATA bytesLeft = 0; 62 | 63 | void spiNMasterInit(void) 64 | { 65 | /* From datasheet Table 50 */ 66 | 67 | /* USART0 SPI Alt. 1: 68 | * SCK = P0_5 69 | * MOSI = P0_3 70 | * MISO = P0_2 71 | */ 72 | 73 | /* USART1 SPI Alt. 2: 74 | * SCK = P1_5 75 | * MOSI = P1_6 76 | * MISO = P1_7 77 | */ 78 | 79 | /* 12.14.2.1: In SPI master mode, only the MOSI, MISO, and SCK should be 80 | * configured as peripherals (see Section 12.4.6.1 and Section 12.4.6.2). If 81 | * the external slave requires a slave select signal (SSN) this can be 82 | * implemented by using a general-purpose I/O pin and control from SW. 83 | */ 84 | 85 | // Note: We do NOT set the mode of the RX pin to "peripheral function" 86 | // because that seems to have no benefits, and is actually bad because 87 | // it disables the internal pull-up resistor. 88 | 89 | #ifdef SPI0 90 | P2DIR &= ~0xC0; // P2DIR.PRIP0 (7:6) = 00 : USART0 takes priority over USART1. 91 | PERCFG &= ~0x01; // PERCFG.U0CFG (0) = 0 (Alt. 1) : USART0 uses alt. location 1. 92 | #else 93 | P2SEL |= 0x40; // USART1 takes priority over USART0 on Port 1. 94 | PERCFG |= 0x02; // PERCFG.U1CFG (1) = 1 (Alt. 2) : USART1 uses alt. location 2. 95 | #endif 96 | 97 | // Assumption: The MODE and SLAVE bits in U0CSR/U1CSR are 0 (the default) so 98 | // the USART is already in SPI Master mode. 99 | 100 | // Set the mode of the SCK and MOSI pins to "peripheral function". 101 | #ifdef SPI0 102 | P0SEL |= ((1<<5) | (1<<3)); // P0SEL.SELP0_5 = 1, P0SEL.SELP0_3 = 1 103 | #else 104 | P1SEL |= ((1<<5) | (1<<6)); // P1SEL.SELP1_5 = 1, P1SEL.SELP1_6 = 1 105 | #endif 106 | 107 | // Below, we set the priority of the RX and TX interrupts to be 1 (second lowest priority). 108 | // They need to be higher than the RF interrupt because that one could take a long time. 109 | // The SPI0 interrupts are grouped with the T2 interrupt, so its priority also gets set. 110 | // The SPI1 interrupts are grouped with the T3 interrupts, so its priority also gets set. 111 | IP0 |= (1< 3000000) 125 | return; 126 | 127 | // 495782 is the largest value that will not overflow the following calculation 128 | while (freq > 495782) 129 | { 130 | baudE++; 131 | freq /= 2; 132 | } 133 | 134 | // calculate baud rate - see datasheet 12.14.3 135 | // this is derived from (baudM + 256) = baud * 2^28 / 24000000 136 | baudMPlus256 = (freq * 11) + (freq * 8663 / 46875); 137 | 138 | // get baudMPlus256 into the range 256-511 (so BAUD_M is in the range 0-255) 139 | while (baudMPlus256 > 0x1ff) 140 | { 141 | baudE++; 142 | baudMPlus256 /= 2; 143 | } 144 | UNGCR &= 0xE0; // preserve CPOL, CPHA, ORDER (7:5) 145 | UNGCR |= baudE; // UNGCR.BAUD_E (4:0) 146 | UNBAUD = baudMPlus256; // UNBAUD.BAUD_M (7:0) - only the lowest 8 bits of baudMPlus256 are used, so this is effectively baudMPlus256 - 256 147 | } 148 | 149 | void spiNMasterSetClockPolarity(BIT polarity) 150 | { 151 | if (polarity == SPI_POLARITY_IDLE_LOW) 152 | { 153 | UNGCR &= ~(1<<7); // SCK idle low (negative polarity) 154 | } 155 | else 156 | { 157 | UNGCR |= (1<<7); // SCK idle high (positive polarity) 158 | } 159 | } 160 | 161 | void spiNMasterSetClockPhase(BIT phase) 162 | { 163 | if (phase == SPI_PHASE_EDGE_LEADING) 164 | { 165 | UNGCR &= ~(1<<6); // data centered on leading (first) edge - rising for idle low, falling for idle high 166 | } 167 | else 168 | { 169 | UNGCR |= (1<<6); // data centered on trailing (second) edge - falling for idle low, rising for idle high 170 | } 171 | } 172 | 173 | void spiNMasterSetBitOrder(BIT bitOrder) 174 | { 175 | if (bitOrder == SPI_BIT_ORDER_LSB_FIRST) 176 | { 177 | UNGCR &= ~(1<<5); // LSB first 178 | } 179 | else 180 | { 181 | UNGCR |= (1<<5); // MSB first 182 | } 183 | } 184 | 185 | BIT spiNMasterBusy(void) 186 | { 187 | return URXNIE; 188 | } 189 | 190 | uint16 spiNMasterBytesLeft(void) 191 | { 192 | uint16 bytes; 193 | 194 | // bytesLeft is 16 bits, so it takes more than one instruction to read. Disable interrupts so it's not updated while we do this 195 | URXNIE = 0; 196 | bytes = bytesLeft; 197 | if (bytes) URXNIE = 1; 198 | 199 | return bytes; 200 | } 201 | 202 | void spiNMasterTransfer(const uint8 XDATA * txBuffer, uint8 XDATA * rxBuffer, uint16 size) 203 | { 204 | if (size) 205 | { 206 | txPointer = txBuffer; 207 | rxPointer = rxBuffer; 208 | bytesLeft = size; 209 | 210 | UNDBUF = *txBuffer; // transmit first byte 211 | URXNIE = 1; // Enable RX interrupt. 212 | } 213 | } 214 | 215 | uint8 spiNMasterSendByte(uint8 XDATA byte) 216 | { 217 | uint8 XDATA rxByte; 218 | 219 | rxPointer = &rxByte; 220 | bytesLeft = 1; 221 | 222 | UNDBUF = byte; 223 | URXNIE = 1; // Enable RX interrupt. 224 | 225 | while (bytesLeft); 226 | return rxByte; 227 | } 228 | 229 | uint8 spiNMasterReceiveByte(void) 230 | { 231 | return spiNMasterSendByte(0xFF); 232 | } 233 | 234 | ISR_URX() 235 | { 236 | URXNIF = 0; 237 | 238 | *rxPointer = UNDBUF; 239 | rxPointer++; 240 | bytesLeft--; 241 | 242 | if (bytesLeft) 243 | { 244 | txPointer++; 245 | UNDBUF = *txPointer; 246 | } 247 | else 248 | { 249 | URXNIE = 0; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /libraries/src/radio_queue/radio_queue.c: -------------------------------------------------------------------------------- 1 | /* radio_queue.c: 2 | * This layer builds on top of radio_mac.c to provide a mechanism for queueing 3 | * RF packets to be sent and packets that are received by this device. It does 4 | * not ensure reliability or specify the format of the packets, except that the 5 | * first byte of the packet must contain its length. 6 | * 7 | * This layer does not transmit packets as quickly as possible; instead, it 8 | * listens for incoming packets for a random interval of 1-4 ms between sending 9 | * packets. 10 | * 11 | * This layer defines the RF packet memory buffers used, and controls access to 12 | * those buffers. 13 | * 14 | * Radio_queue is essentially a stripped-down version of the radio_link 15 | * library, so radio_link is a good alternative if you want a more specialized 16 | * implementation with more features. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | /* PARAMETERS *****************************************************************/ 25 | 26 | int32 CODE param_radio_channel = 128; 27 | 28 | static int32 channel_number = 0; 29 | static volatile BIT channel_select = 0; 30 | 31 | /* PACKET VARIABLES AND DEFINES ***********************************************/ 32 | 33 | // Compute the max size of on-the-air packets. This value is stored in the PKTLEN register. 34 | #define RADIO_MAX_PACKET_SIZE (RADIO_QUEUE_PAYLOAD_SIZE) 35 | 36 | #define RADIO_QUEUE_PACKET_LENGTH_OFFSET 0 37 | 38 | /* rxPackets: 39 | * We need to be prepared at all times to receive a full packet from another 40 | * party, even if we cannot give it to the main loop. Therefore, we need (at 41 | * least) THREE buffers, so that two can be owned by the main loop while 42 | * another is owned by the ISR and ready to receive the next packet. 43 | * 44 | * If a packet is received and the main loop still owns the other two buffers, 45 | * we discard it. 46 | * 47 | * Ownership of the RX packet buffers is determined from radioQueueRxMainLoopIndex and radioQueueRxInterruptIndex. 48 | * The main loop owns all the buffers from radioQueueRxMainLoopIndex to radioQueueRxInterruptIndex-1 inclusive. 49 | * If the two indices are equal, then the main loop owns nothing. Here are three examples: 50 | * 51 | * radioQueueRxMainLoopIndex | radioQueueRxInterruptIndex | Buffers owned by main loop. 52 | * 0 | 0 | None 53 | * 0 | 1 | rxBuffer[0] 54 | * 0 | 2 | rxBuffer[0 and 1] 55 | */ 56 | #define RX_PACKET_COUNT 3 57 | static volatile uint8 XDATA radioQueueRxPacket[RX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE + 2]; // The first byte is the length. 58 | static volatile uint8 DATA radioQueueRxMainLoopIndex = 0; // The index of the next rxBuffer to read from the main loop. 59 | static volatile uint8 DATA radioQueueRxInterruptIndex = 0; // The index of the next rxBuffer to write to when a packet comes from the radio. 60 | 61 | /* txPackets are handled similarly */ 62 | #define TX_PACKET_COUNT 16 63 | static volatile uint8 XDATA radioQueueTxPacket[TX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE]; // The first byte is the length. 64 | static volatile uint8 DATA radioQueueTxMainLoopIndex = 0; // The index of the next txPacket to write to in the main loop. 65 | static volatile uint8 DATA radioQueueTxInterruptIndex = 0; // The index of the current txPacket we are trying to send on the radio. 66 | 67 | BIT radioQueueAllowCrcErrors = 0; 68 | 69 | /* GENERAL FUNCTIONS **********************************************************/ 70 | 71 | void radioQueueInit() 72 | { 73 | randomSeedFromSerialNumber(); 74 | 75 | PKTLEN = RADIO_MAX_PACKET_SIZE; 76 | if (channel_select) 77 | {CHANNR = channel_number;} 78 | else 79 | {CHANNR = param_radio_channel;} 80 | 81 | radioMacInit(); 82 | radioMacStrobe(); 83 | } 84 | 85 | // Returns a random delay in units of 0.922 ms (the same units of radioMacRx). 86 | // This is used to decide when to next transmit a queued data packet. 87 | static uint8 randomTxDelay() 88 | { 89 | return 1 + (randomNumber() & 3); 90 | } 91 | 92 | /* TX FUNCTIONS (called by higher-level code in main loop) ********************/ 93 | 94 | uint8 radioQueueTxAvailable(void) 95 | { 96 | // Assumption: TX_PACKET_COUNT is a power of 2 97 | return (radioQueueTxInterruptIndex - radioQueueTxMainLoopIndex - 1) & (TX_PACKET_COUNT - 1); 98 | } 99 | 100 | uint8 radioQueueTxQueued(void) 101 | { 102 | return (radioQueueTxMainLoopIndex - radioQueueTxInterruptIndex) & (TX_PACKET_COUNT - 1); 103 | } 104 | 105 | uint8 XDATA * radioQueueTxCurrentPacket() 106 | { 107 | if (!radioQueueTxAvailable()) 108 | { 109 | return 0; 110 | } 111 | 112 | return radioQueueTxPacket[radioQueueTxMainLoopIndex]; 113 | } 114 | 115 | void radioQueueTxSendPacket(void) 116 | { 117 | // Update our index of which packet to populate in the main loop. 118 | if (radioQueueTxMainLoopIndex == TX_PACKET_COUNT - 1) 119 | { 120 | radioQueueTxMainLoopIndex = 0; 121 | } 122 | else 123 | { 124 | radioQueueTxMainLoopIndex++; 125 | } 126 | 127 | // Make sure that radioMacEventHandler runs soon so it can see this new data and send it. 128 | // This must be done LAST. 129 | radioMacStrobe(); 130 | } 131 | 132 | /* RX FUNCTIONS (called by higher-level code in main loop) ********************/ 133 | 134 | uint8 XDATA * radioQueueRxCurrentPacket(void) 135 | { 136 | if (radioQueueRxMainLoopIndex == radioQueueRxInterruptIndex) 137 | { 138 | return 0; 139 | } 140 | return radioQueueRxPacket[radioQueueRxMainLoopIndex]; 141 | } 142 | 143 | void radioQueueRxDoneWithPacket(void) 144 | { 145 | if (radioQueueRxMainLoopIndex == RX_PACKET_COUNT - 1) 146 | { 147 | radioQueueRxMainLoopIndex = 0; 148 | } 149 | else 150 | { 151 | radioQueueRxMainLoopIndex++; 152 | } 153 | } 154 | 155 | /* FUNCTIONS CALLED IN RF_ISR *************************************************/ 156 | 157 | static void takeInitiative() 158 | { 159 | if (radioQueueTxInterruptIndex != radioQueueTxMainLoopIndex) 160 | { 161 | // Try to send the next data packet. 162 | radioMacTx(radioQueueTxPacket[radioQueueTxInterruptIndex]); 163 | } 164 | else 165 | { 166 | radioMacRx(radioQueueRxPacket[radioQueueRxInterruptIndex], 0); 167 | } 168 | } 169 | 170 | void radioMacEventHandler(uint8 event) // called by the MAC in an ISR 171 | { 172 | if (event == RADIO_MAC_EVENT_STROBE) 173 | { 174 | takeInitiative(); 175 | return; 176 | } 177 | else if (event == RADIO_MAC_EVENT_TX) 178 | { 179 | // Give ownership of the current TX packet back to the main loop by updated radioQueueTxInterruptIndex. 180 | if (radioQueueTxInterruptIndex == TX_PACKET_COUNT - 1) 181 | { 182 | radioQueueTxInterruptIndex = 0; 183 | } 184 | else 185 | { 186 | radioQueueTxInterruptIndex++; 187 | } 188 | 189 | // We sent a packet, so now let's give another party a chance to talk. 190 | radioMacRx(radioQueueRxPacket[radioQueueRxInterruptIndex], randomTxDelay()); 191 | return; 192 | } 193 | else if (event == RADIO_MAC_EVENT_RX) 194 | { 195 | uint8 XDATA * currentRxPacket = radioQueueRxPacket[radioQueueRxInterruptIndex]; 196 | 197 | if (!radioQueueAllowCrcErrors && !radioCrcPassed()) 198 | { 199 | if (radioQueueTxInterruptIndex != radioQueueTxMainLoopIndex) 200 | { 201 | radioMacRx(currentRxPacket, randomTxDelay()); 202 | } 203 | else 204 | { 205 | radioMacRx(currentRxPacket, 0); 206 | } 207 | return; 208 | } 209 | 210 | if (currentRxPacket[RADIO_QUEUE_PACKET_LENGTH_OFFSET] > 0) 211 | { 212 | // We received a packet that contains actual data. 213 | 214 | uint8 nextradioQueueRxInterruptIndex; 215 | 216 | // See if we can give the data to the main loop. 217 | if (radioQueueRxInterruptIndex == RX_PACKET_COUNT - 1) 218 | { 219 | nextradioQueueRxInterruptIndex = 0; 220 | } 221 | else 222 | { 223 | nextradioQueueRxInterruptIndex = radioQueueRxInterruptIndex + 1; 224 | } 225 | 226 | if (nextradioQueueRxInterruptIndex != radioQueueRxMainLoopIndex) 227 | { 228 | // We can accept this packet! 229 | radioQueueRxInterruptIndex = nextradioQueueRxInterruptIndex; 230 | } 231 | } 232 | 233 | takeInitiative(); 234 | return; 235 | } 236 | else if (event == RADIO_MAC_EVENT_RX_TIMEOUT) 237 | { 238 | takeInitiative(); 239 | return; 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /libraries/include/usb_hid.h: -------------------------------------------------------------------------------- 1 | /*! \file usb_hid.h 2 | * The usb_hid.lib library implements a composite USB device 3 | * containing a keyboard interface and a mouse interface using the 4 | * Human Interface Device (HID) class. 5 | * 6 | * You can find the specification of the USB HID device class in HID1_11.pdf, 7 | * available for download from USB Implementers Forum at this url: 8 | * http://www.usb.org/developers/hidpage 9 | * 10 | * A complete list of Usage tags used in HID reports, which define the format of 11 | * the input and output data used by this library, can be found in Hut1_12.pdf 12 | * on the same page. 13 | * 14 | * (A listing of all class specification documents is at 15 | * http://www.usb.org/devclass_docs) 16 | */ 17 | 18 | #ifndef _USB_HID_H 19 | #define _USB_HID_H 20 | 21 | #include "usb_hid_constants.h" 22 | #include 23 | 24 | /*! \struct HID_KEYBOARD_OUT_REPORT 25 | * This struct contains the \b output data sent in HID reports from the host to 26 | * the \b keyboard interface. 27 | * If the Wixel is connected to a Windows machine, you can use this struct to 28 | * determine whether the Caps Lock, Num Lock, or Scroll Lock options are active. 29 | * This might not work on Linux or Mac OS computers. */ 30 | typedef struct HID_KEYBOARD_OUT_REPORT 31 | { 32 | /*! Keyboard LED indicator data. Each bit contains the state of one 33 | * indicator (1 = on, 0 = off), with the lowest bit representing Num Lock 34 | * (usage ID 0x01) and the highest bit representing Do Not Disturb (usage ID 35 | * 0x08) in the LED usage Page. See usb_hid_constants.h for the meaning 36 | * of each bit. The keyboard's HID Report Descriptor is defined as 37 | * keyboardReportDescriptor in usb_hid.c. 38 | * 39 | * Example usage: 40 | \code 41 | if (usbHidKeyboardOutput.leds & (1<keyboardReportDescriptor in 63 | * usb_hid.c. */ 64 | uint8 modifiers; 65 | uint8 _reserved; 66 | /*! Keyboard key code data: Each byte contains the key code of one key that 67 | * is currently pressed (0 = no key). Up to 6 pressed keys at a time can be 68 | * reported in this way. See \ref usb_hid_constants.h for possible key code 69 | * values. The keyboard's HID Report Descriptor is defined as 70 | * keyboardReportDescriptor in usb_hid.c. */ 71 | uint8 keyCodes[6]; 72 | } HID_KEYBOARD_IN_REPORT; 73 | 74 | /*! \struct HID_MOUSE_IN_REPORT 75 | * This struct contains the \b output data sent in HID reports from the host to 76 | * the \b keyboard interface. */ 77 | typedef struct HID_MOUSE_IN_REPORT 78 | { 79 | /*! Mouse button data: Each bit contains the state of one button (1 = 80 | * pressed, 0 = not pressed), with the lowest bit representing Button 1 81 | * (usage ID 0x01) and the highest bit representing Button 8 (usage ID 82 | * 0x08). Buttons 1, 2, and 3 usually correspond to the left, right, and 83 | * middle buttons on a mouse, respectively. See \ref usb_hid_constants.h for 84 | * the meaning of each bit. The mouse's HID Report Descriptor is defined as 85 | * mouseReportDescriptor in usb_hid.c. */ 86 | uint8 buttons; 87 | /*! Mouse X axis data: This byte contains an 8-bit signed value that 88 | * represents a change (relative offset) in the horizontal position of the 89 | * mouse cursor. */ 90 | int8 x; 91 | /*! Mouse Y axis data: This byte contains an 8-bit signed value that 92 | * represents a change (relative offset) in the vertical position of the 93 | * mouse cursor. */ 94 | int8 y; 95 | /*! Mouse wheel data: This byte contains an 8-bit signed value that 96 | * represents a change (relative offset) in the position of the mouse wheel. 97 | */ 98 | int8 wheel; 99 | } HID_MOUSE_IN_REPORT; 100 | 101 | /*! \struct HID_JOYSTICK_IN_REPORT 102 | * This struct contains \b input data sent in HID reports from the 103 | * device's joystick interface to the host. */ 104 | typedef struct HID_JOYSTICK_IN_REPORT 105 | { 106 | int16 x; /*!< Joystick X axis position. Valid values are from -32767 to 32767. */ 107 | int16 y; /*!< Joystick Y axis position. Valid values are from -32767 to 32767. */ 108 | int16 z; /*!< Joystick Z axis position. Valid values are from -32767 to 32767. */ 109 | int16 rx; /*!< Joystick's rotation about the X axis. Valid values are from -32767 to 32767. */ 110 | int16 ry; /*!< Joystick's rotation about the Y axis. Valid values are from -32767 to 32767. */ 111 | int16 rz; /*!< Joystick's rotation about the Z axis. Valid values are from -32767 to 32767. */ 112 | int16 slider; /*!< Joystick's slider position. Valid values are from -32767 to 32767. */ 113 | int16 dial; /*!< Joystick's dial position. Valid values are from -32767 to 32767. */ 114 | 115 | uint32 buttons; /*!< A bit map that specifies which buttons are pressed. */ 116 | } HID_JOYSTICK_IN_REPORT; 117 | 118 | /*! Contains \b output data received by the \b keyboard interface from the host. 119 | * If the Wixel is connected to a Windows machine, you can use this variable to 120 | * determine whether the Caps Lock, Num Lock, or Scroll Lock options are active. 121 | * This might not work on Linux or Mac OS computers. 122 | * See HID_KEYBOARD_OUT_REPORT for details. */ 123 | extern HID_KEYBOARD_OUT_REPORT XDATA usbHidKeyboardOutput; 124 | 125 | /*! Contains \b input data to be sent from the \b keyboard interface to the host. 126 | * You can use this variable to send key presses to the computer. 127 | * After writing data to this struct, set #usbHidKeyboardInputUpdated to 1 to 128 | * tell the HID library to send that data to the computer. 129 | * See HID_KEYBOARD_IN_REPORT for details. */ 130 | extern HID_KEYBOARD_IN_REPORT XDATA usbHidKeyboardInput; 131 | 132 | /*! Contains \b input data to be sent from the \b mouse interface to the host. 133 | * You can use this variable to send X, Y and mouse wheel position changes to 134 | * the computer and report the state of the mouse buttons. 135 | * After writing data to this variable, set #usbHidMouseInputUpdated to 1 to 136 | * tell the HID library to send that data to the computer. 137 | * See HID_MOUSE_IN_REPORT for details. */ 138 | extern HID_MOUSE_IN_REPORT XDATA usbHidMouseInput; 139 | 140 | /*! Contains \b input data sent in HID reports from the 141 | * device's joystick interface to the host. 142 | * You can use this variable to send joystick position and button data to 143 | * the USB host. 144 | * After writing data to this variable, set #usbHidJoystickInputUpdated to 1 145 | * to tell the HID library to send that data to the computer. */ 146 | extern HID_JOYSTICK_IN_REPORT XDATA usbHidJoystickInput; 147 | 148 | /*! After writing data to #usbHidKeyboardInput, set this bit to 1 to trigger an HID 149 | * report to be sent from the keyboard interface to the host. This bit is cleared 150 | * by the library once the report is sent. */ 151 | extern BIT usbHidKeyboardInputUpdated; 152 | 153 | /*! After writing data to #usbHidMouseInput, set this bit to 1 to trigger an HID 154 | * report to be sent from the mouse interface to the host. This bit is cleared by the 155 | * library once the report is sent. */ 156 | extern BIT usbHidMouseInputUpdated; 157 | 158 | /*! After writing data to #usbHidJoystickInput, set this bit to 1 to trigger an HID 159 | * report to be sent from the joystick interface to the host. This bit is cleared by the 160 | * library once the report is sent. */ 161 | extern BIT usbHidJoystickInputUpdated; 162 | 163 | /*! This must be called regularly if you are implementing an HID device. */ 164 | void usbHidService(void); 165 | 166 | /*! Converts an ASCII-encoded character into the corresponding HID Key Code, 167 | * suitable for the keyCodes array in HID_KEYBOARD_IN_REPORT. 168 | * Note that many pairs of ASCII characters map to the same key code because 169 | * they are on the same key. 170 | * For example, both '4' and '$' map to 0x21 (KEY_4). 171 | * To send a dollar sign to the computer, you must set the shift bit of the 172 | * modifiers byte in the HID_KEYBOARD_IN_REPORT. */ 173 | uint8 usbHidKeyCodeFromAsciiChar(char asciiChar); 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /libraries/src/radio_com/radio_com.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PAYLOAD_TYPE_DATA 0 5 | #define PAYLOAD_TYPE_CONTROL_SIGNALS 1 6 | 7 | BIT radioComRxEnforceOrdering = 0; 8 | 9 | static uint8 DATA txBytesLoaded = 0; 10 | static uint8 DATA rxBytesLeft = 0; 11 | 12 | static uint8 XDATA * DATA rxPointer = 0; 13 | static uint8 XDATA * DATA txPointer = 0; 14 | static uint8 XDATA * DATA packetPointer = 0; 15 | 16 | static uint8 radioComRxSignals = 0; 17 | static uint8 radioComTxSignals = 0; 18 | static uint8 lastRxSignals = 0; // The last RX signals sent to the higher-level code. 19 | static BIT sendSignalsSoon = 0; // 1 iff we should transmit control signals soon 20 | 21 | // For highest throughput, we want to send as much data in each packet 22 | // as possible. But for lower latency, we sometimes need to send packets 23 | // that are NOT full. 24 | // This library will only send non-full packets if the number of packets 25 | // currently queued to be sent is small. Specifically, that number must 26 | // not exceed TX_QUEUE_THRESHOLD. 27 | // A higher threshold means that there will be more under-populated packets 28 | // at the beginning of a data transfer (which is bad), but slightly reduces 29 | // the importance of calling radioComTxService often (which can be good). 30 | #define TX_QUEUE_THRESHOLD 1 31 | 32 | void radioComInit() 33 | { 34 | radioLinkInit(); 35 | } 36 | 37 | /** RX FUNCTIONS **************************************************************/ 38 | 39 | #define WAITING_TO_REPORT_RX_SIGNALS (radioComRxEnforceOrdering && radioComRxSignals != lastRxSignals) 40 | 41 | static void receiveMorePackets(void) 42 | { 43 | uint8 XDATA * packet; 44 | 45 | if (rxBytesLeft != 0) 46 | { 47 | // There are bytes available. The higher-level code should 48 | // call radioComRxReceiveByte to get them. 49 | return; 50 | } 51 | 52 | if (WAITING_TO_REPORT_RX_SIGNALS) 53 | { 54 | // The higher-level code needs to call radioComRxSignals before 55 | // we feed it any more data. 56 | return; 57 | } 58 | 59 | // Each iteration of this loop processes one packet received on the radio. 60 | // This loop stops when we are out of packets or when we received a packet 61 | // that contains some information that the higher-level code needs to process. 62 | while(packet = radioLinkRxCurrentPacket()) 63 | { 64 | switch(radioLinkRxCurrentPayloadType()) 65 | { 66 | case PAYLOAD_TYPE_DATA: 67 | // We received some data. Populate rxPointer and rxBytesLeft. 68 | // The data can be retreived with radioComRxAvailable and racioComRxReceiveByte(). 69 | 70 | // Assumption: radioLink doesn't ever return zero-length packets, 71 | // so rxBytesLeft is non-zero now and we don't have to worry about 72 | // discard zero-length packets in radio_com.c. 73 | rxBytesLeft = packet[0]; // Read the packet length. 74 | rxPointer = packet+1; // Make rxPointer point to the data. 75 | return; 76 | 77 | case PAYLOAD_TYPE_CONTROL_SIGNALS: 78 | // We received a command to set the control signals. 79 | radioComRxSignals = packet[1]; 80 | 81 | radioLinkRxDoneWithPacket(); 82 | 83 | if (WAITING_TO_REPORT_RX_SIGNALS) 84 | { 85 | // The higher-level code has not seen these values for the control 86 | // signals yet, so stop processing packets. 87 | // The higher-level code can access these values by calling radioComRxControlSignals(). 88 | return; 89 | } 90 | 91 | // It was a redundant command so don't do anything special. 92 | // Keep processing packets. 93 | break; 94 | } 95 | } 96 | } 97 | 98 | // NOTE: This function only returns the number of bytes available in the CURRENT PACKET. 99 | // It doesn't look at all the packets received, and it doesn't count the data that is 100 | // queued on the other Wixel. Therefore, it is never recommended to write some kind of 101 | // program that waits for radioComRxAvailable to reach some value greater than 1: it might 102 | // never reach that value. 103 | uint8 radioComRxAvailable(void) 104 | { 105 | receiveMorePackets(); 106 | return rxBytesLeft; 107 | } 108 | 109 | // Assumption: The user recently called radioComRxAvailable and it returned 110 | // a non-zero value. 111 | uint8 radioComRxReceiveByte(void) 112 | { 113 | uint8 tmp = *rxPointer; // Read a byte from the current RX packet. 114 | rxPointer++; // Update pointer and counter. 115 | rxBytesLeft--; 116 | 117 | if (rxBytesLeft == 0) // If there are no bytes left in this packet... 118 | { 119 | radioLinkRxDoneWithPacket(); // Tell the radio link layer we are done with it so we can receive more. 120 | } 121 | 122 | return tmp; 123 | } 124 | 125 | uint8 radioComRxControlSignals(void) 126 | { 127 | receiveMorePackets(); 128 | lastRxSignals = radioComRxSignals; 129 | return lastRxSignals; 130 | } 131 | 132 | /** TX FUNCTIONS **************************************************************/ 133 | 134 | static void radioComSendDataNow() 135 | { 136 | *packetPointer = txBytesLoaded; 137 | radioLinkTxSendPacket(PAYLOAD_TYPE_DATA); 138 | txBytesLoaded = 0; 139 | } 140 | 141 | static void radioComSendControlSignalsNow() 142 | { 143 | // Assumption: txBytesLoaded is 0 (we are not in the middle of populating a data packet) 144 | // Assumption: radioLinkTxAvailable() >= 1 145 | 146 | uint8 XDATA * packet; 147 | 148 | packet = radioLinkTxCurrentPacket(); 149 | packet[0] = 1; // Payload length is one byte. 150 | packet[1] = radioComTxSignals; 151 | sendSignalsSoon = 0; 152 | radioLinkTxSendPacket(PAYLOAD_TYPE_CONTROL_SIGNALS); 153 | } 154 | 155 | void radioComTxService(void) 156 | { 157 | if (radioLinkResetPacketReceived) 158 | { 159 | // The other device has sent us a reset packet, which means it has been 160 | // reset. We should send the state of the control signals to it. 161 | radioLinkResetPacketReceived = 0; 162 | sendSignalsSoon = 1; 163 | } 164 | 165 | if (sendSignalsSoon) 166 | { 167 | // We want to send the control signals ASAP. 168 | 169 | // NOTE: The if statement below could probably be moved to radioComTxControlSignals() 170 | // and then you could add the assumption here that txBytesLoaded is 0 171 | // (we are not in the middle of populating a data packet). 172 | if (txBytesLoaded != 0) 173 | { 174 | // There is normal data that needs to be sent before the control signals, 175 | // so send it now. 176 | radioComSendDataNow(); 177 | } 178 | 179 | if (radioLinkTxAvailable()) 180 | { 181 | radioComSendControlSignalsNow(); 182 | } 183 | } 184 | else 185 | { 186 | // We don't need to send control signals ASAP, so we use the normal policy 187 | // for sending data: only send a non-full packet if the number of packets 188 | // queued in the lower level drops below the TX_QUEUE_THRESHOLD. 189 | 190 | if (txBytesLoaded != 0 && radioLinkTxQueued() <= TX_QUEUE_THRESHOLD) 191 | { 192 | radioComSendDataNow(); 193 | } 194 | } 195 | } 196 | 197 | uint8 radioComTxAvailable(void) 198 | { 199 | if (sendSignalsSoon) 200 | { 201 | // We want to send the control signals ASAP, but have not yet been able to 202 | // queue a packet for them. Return 0 because we don't want to accept any 203 | // more data bytes until we queue up those control signals. This is part of 204 | // the plan to ensure that everything is processed in the right order. 205 | return 0; 206 | } 207 | else 208 | { 209 | // Assumption: If txBytesLoaded is non-zero, radioLinkTxAvailable will be non-zero, 210 | // so the subtraction below does not overflow. 211 | // Assumption: The multiplication below does not overflow ever. 212 | return radioLinkTxAvailable()*RADIO_LINK_PAYLOAD_SIZE - txBytesLoaded; 213 | } 214 | } 215 | 216 | void radioComTxSendByte(uint8 byte) 217 | { 218 | // Assumption: The user called radioComTxAvailable recently and it returned a non-zero value. 219 | if (txBytesLoaded == 0) 220 | { 221 | txPointer = packetPointer = radioLinkTxCurrentPacket(); 222 | } 223 | 224 | txPointer++; 225 | *txPointer = byte; 226 | txBytesLoaded++; 227 | 228 | if (txBytesLoaded == RADIO_LINK_PAYLOAD_SIZE) 229 | { 230 | radioComSendDataNow(); 231 | } 232 | } 233 | 234 | // If we are in the middle of building a packet, send it. 235 | void radioComTxControlSignals(uint8 controlSignals) 236 | { 237 | if(controlSignals != radioComTxSignals) 238 | { 239 | radioComTxSignals = controlSignals; 240 | sendSignalsSoon = 1; 241 | radioComTxService(); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /libraries/src/wixel/sleep.c: -------------------------------------------------------------------------------- 1 | // sleep.c: Basic functions to put the board into low power modes (sleep) 2 | // and switch oscillators. See the datasheet or design note DN106 for more 3 | // information about the different power modes and their impact. 4 | // This code is based primarily on the samples provided in the previously listed 5 | // design note by Torgeir Sundet 6 | 7 | #include 8 | #include 9 | 10 | // Initialization of source buffers and DMA descriptor for the DMA transfer 11 | unsigned char XDATA PM2_BUF[7] = {0x06,0x06,0x06,0x06,0x06,0x06,0x04}; 12 | unsigned char XDATA PM3_BUF[7] = {0x07,0x07,0x07,0x07,0x07,0x07,0x04}; 13 | unsigned char XDATA dmaDesc[8] = {0x00,0x00,0xDF,0xBE,0x00,0x07,0x20,0x42}; 14 | 15 | void sleepInit(void) 16 | { 17 | WORIRQ |= (1<<4); // Enable Event0 interrupt 18 | } 19 | 20 | ISR(ST, 1) 21 | { 22 | // Clear IRCON.STIF (Sleep Timer CPU interrupt flag) 23 | IRCON &= 0x7F; 24 | // Clear WORIRQ.EVENT0_FLAG (Sleep Timer peripheral interrupt flag) 25 | // This is required for the CC111xFx/CC251xFx only! 26 | WORIRQ &= 0xFE; 27 | 28 | SLEEP &= 0xFC; // Not required when resuming from PM0; Clear SLEEP.MODE[1:0] 29 | } 30 | 31 | void switchToRCOSC(void) 32 | { 33 | // Power up [HS RCOSC] (SLEEP.OSC_PD = 0) 34 | SLEEP &= ~0x04; 35 | // Wait until [HS RCOSC] is stable (SLEEP.HFRC_STB = 1) 36 | while ( ! (SLEEP & 0x20) ); 37 | // Switch system clock source to HS RCOSC (CLKCON.OSC = 1), 38 | // and set max CPU clock speed (CLKCON.CLKSPD = 1). 39 | CLKCON = (CLKCON & ~0x07) | 0x40 | 0x01; 40 | // Wait until system clock source has actually changed (CLKCON.OSC = 1) 41 | while ( !(CLKCON & 0x40) ); 42 | // Power down [HS XOSC] (SLEEP.OSC_PD = 1) 43 | SLEEP |= 0x04; 44 | } 45 | 46 | void sleepMode1(uint16 seconds) 47 | { 48 | unsigned char temp; 49 | unsigned short desired_event0; 50 | 51 | desired_event0 = seconds; 52 | 53 | // set Sleep Timer to the lowest resolution (1 second) 54 | WORCTRL |= 0x03; // WOR_RES[1:0] 55 | // make sure interrupts aren't completely disabled 56 | // and enable sleep timer interrupt 57 | IEN0 |= 0xA0; // Set EA and STIE bits 58 | 59 | WORCTRL |= 0x04; // Reset Sleep Timer; WOR_RESET 60 | temp = WORTIME0; 61 | while(temp == WORTIME0); // Wait until a positive 32 kHz edge 62 | temp = WORTIME0; 63 | while(temp == WORTIME0); // Wait until a positive 32 kHz edge 64 | WOREVT1 = desired_event0 >> 8; // Set EVENT0, high byte 65 | WOREVT0 = desired_event0; // Set EVENT0, low byte 66 | 67 | // Set SLEEP.MODE according to PM1 68 | SLEEP = (SLEEP & 0xFC) | 0x01; // SLEEP.MODE[1:0] 69 | 70 | // Apply three NOPs to allow the corresponding interrupt blocking to take 71 | // effect, before verifying the SLEEP.MODE bits below. Note that all 72 | // interrupts are blocked when SLEEP.MODE ≠ 0, thus the time between 73 | // setting SLEEP.MODE ≠ 0, and asserting PCON.IDLE should be as short as 74 | // possible. If an interrupt occurs before the NOPs have completed, then 75 | // the enabled ISR shall clear the SLEEP.MODE bits, according to the code 76 | // in Figure 7. 77 | 78 | __asm nop __endasm; 79 | __asm nop __endasm; 80 | __asm nop __endasm; 81 | 82 | // If no interrupt was executed in between the above NOPs, then all 83 | // interrupts are effectively blocked when reaching this code position. 84 | // If the SLEEP.MODE bits have been cleared at this point, which means 85 | // that an ISR has indeed executed in between the above NOPs, then the 86 | // application will not enter PM{1 – 3} ! 87 | 88 | if (SLEEP & 0x03) // SLEEP.MODE[1:0] 89 | { 90 | // Set PCON.IDLE to enter the selected PM, e.g. PM1. 91 | PCON |= 0x01; 92 | // The SoC is now in PM and will only wake up upon Sleep Timer interrupt 93 | // or external Port interrupt. 94 | __asm nop __endasm; 95 | } 96 | 97 | // Switch back to high speed 98 | boardClockInit(); 99 | } 100 | 101 | void sleepMode2(uint16 seconds) 102 | { 103 | unsigned char temp; 104 | unsigned short desired_event0; 105 | 106 | unsigned char storedDescHigh, storedDescLow; 107 | BIT storedDma0Armed; 108 | unsigned char storedIEN0, storedIEN1, storedIEN2; 109 | 110 | desired_event0 = seconds; 111 | 112 | // set Sleep Timer to the lowest resolution (1 second) 113 | WORCTRL |= 0x03; 114 | // must be using RC OSC before going to PM2 115 | switchToRCOSC(); 116 | 117 | // Following DMA code is a workaround for a bug described in Design Note 118 | // DN106 section 4.1.4 where there is a small chance that the sleep mode 119 | // bits are faulty set to a value other than zero and this prevents the 120 | // processor from waking up correctly (appears to hang) 121 | 122 | // Store current DMA channel 0 descriptor and abort any ongoing transfers, 123 | // if the channel is in use. 124 | storedDescHigh = DMA0CFGH; 125 | storedDescLow = DMA0CFGL; 126 | storedDma0Armed = DMAARM & 0x01; 127 | DMAARM |= 0x81; // Abort transfers on DMA Channel 0; Set ABORT and DMAARM0 128 | // Update descriptor with correct source. 129 | dmaDesc[0] = ((unsigned int)& PM2_BUF) >> 8; 130 | dmaDesc[1] = (unsigned int)& PM2_BUF; 131 | // Associate the descriptor with DMA channel 0 and arm the DMA channel 132 | DMA0CFGH = ((unsigned int)&dmaDesc) >> 8; 133 | DMA0CFGL = (unsigned int)&dmaDesc; 134 | DMAARM = 0x01; // Arm Channel 0; DMAARM0 135 | 136 | // save enabled interrupts 137 | storedIEN0 = IEN0; 138 | storedIEN1 = IEN1; 139 | storedIEN2 = IEN2; 140 | 141 | // make sure interrupts aren't completely disabled 142 | // and enable sleep timer interrupt 143 | IEN0 |= 0xA0; // Set EA and STIE bits 144 | 145 | // then disable all interrupts except the sleep timer 146 | IEN0 &= 0xA0; 147 | IEN1 &= ~0x3F; 148 | IEN2 &= ~0x3F; 149 | 150 | WORCTRL |= 0x04; // Reset Sleep Timer 151 | temp = WORTIME0; 152 | while(temp == WORTIME0); // Wait until a positive 32 kHz edge 153 | temp = WORTIME0; 154 | while(temp == WORTIME0); // Wait until a positive 32 kHz edge 155 | WOREVT1 = desired_event0 >> 8; // Set EVENT0, high byte 156 | WOREVT0 = desired_event0; // Set EVENT0, low byte 157 | 158 | MEMCTR |= 0x02; // Flash cache must be disabled. 159 | SLEEP = 0x06; // PM2, disable USB, power down other oscillators 160 | 161 | __asm nop __endasm; 162 | __asm nop __endasm; 163 | __asm nop __endasm; 164 | 165 | if (SLEEP & 0x03) 166 | { 167 | __asm mov 0xD7,#0x01 __endasm; // DMAREQ = 0x01; 168 | __asm nop __endasm; // Needed to perfectly align the DMA transfer. 169 | __asm orl 0x87,#0x01 __endasm; // PCON |= 0x01; 170 | __asm nop __endasm; 171 | } 172 | 173 | // restore enabled interrupts 174 | IEN0 = storedIEN0; 175 | IEN1 = storedIEN1; 176 | IEN2 = storedIEN2; 177 | 178 | // restore DMA descriptor 179 | DMA0CFGH = storedDescHigh; 180 | DMA0CFGL = storedDescLow; 181 | if (storedDma0Armed) 182 | DMAARM |= 0x01; // Set DMA0ARM 183 | 184 | // Switch back to high speed 185 | boardClockInit(); 186 | } 187 | 188 | 189 | void sleepMode3(void) 190 | { 191 | unsigned char storedDescHigh, storedDescLow; 192 | BIT storedDma0Armed; 193 | 194 | // set Sleep Timer to the lowest resolution (1 second) 195 | WORCTRL |= 0x03; 196 | // must be using RC OSC before going to PM3 197 | switchToRCOSC(); 198 | 199 | // Following DMA code is a workaround for a bug described in Design Note 200 | // DN106 section 4.1.4 where there is a small chance that the sleep mode 201 | // bits are faulty set to a value other than zero and this prevents the 202 | // processor from waking up correctly (appears to hang) 203 | 204 | // Store current DMA channel 0 descriptor and abort any ongoing transfers, 205 | // if the channel is in use. 206 | storedDescHigh = DMA0CFGH; 207 | storedDescLow = DMA0CFGL; 208 | storedDma0Armed = DMAARM & 0x01; 209 | DMAARM |= 0x81; // Abort transfers on DMA Channel 0; Set ABORT and DMAARM0 210 | // Update descriptor with correct source. 211 | dmaDesc[0] = ((unsigned int)& PM3_BUF) >> 8; 212 | dmaDesc[1] = (unsigned int)& PM3_BUF; 213 | // Associate the descriptor with DMA channel 0 and arm the DMA channel 214 | DMA0CFGH = ((unsigned int)&dmaDesc) >> 8; 215 | DMA0CFGL = (unsigned int)&dmaDesc; 216 | DMAARM = 0x01; // Arm Channel 0; DMAARM0 217 | 218 | // make sure interrupts aren't completely disabled 219 | IEN0 |= (1<<7); 220 | 221 | MEMCTR |= 0x02; // Flash cache must be disabled. 222 | SLEEP = 0x07; // PM3, disable USB, power down other oscillators 223 | 224 | __asm nop __endasm; 225 | __asm nop __endasm; 226 | __asm nop __endasm; 227 | 228 | if (SLEEP & 0x03) 229 | { 230 | __asm mov 0xD7,#0x01 __endasm; // DMAREQ = 0x01; 231 | __asm nop __endasm; // Needed to perfectly align the DMA transfer. 232 | __asm orl 0x87,#0x01 __endasm; // PCON |= 0x01; 233 | __asm nop __endasm; 234 | } 235 | 236 | // restore DMA descriptor 237 | DMA0CFGH = storedDescHigh; 238 | DMA0CFGL = storedDescLow; 239 | if (storedDma0Armed) 240 | DMAARM |= 0x01; // Set DMA0ARM 241 | 242 | // Switch back to high speed 243 | boardClockInit(); 244 | } 245 | 246 | -------------------------------------------------------------------------------- /libraries/include/gpio.h: -------------------------------------------------------------------------------- 1 | /*! \file gpio.h 2 | * 3 | * The gpio.lib library provides functions for using the CC2511's pins 4 | * as general purpose inputs or outputs (GPIO). Every pin on the CC2511 that has a 5 | * name starting with P can be configured as a digital input or digital output. 6 | * 7 | * The functions in this library allow for simpler programmatic approaches to working 8 | * with digital I/O since you no longer have to deal with a multitude of pin-specific 9 | * registers. 10 | * 11 | * \section ports Ports 12 | * 13 | * The pins on the CC2511 are divided into three ports: Port 0 (P0), Port 1 (P1), 14 | * and Port 2 (P2). Every pin's name is prefixed by the name of the port it is on. 15 | * For example, P0_3 starts with "P0" so it is a pin on Port 0. 16 | * 17 | * On the Wixel, none of the pins on Port 0 and Port 1 are tied to any on-board 18 | * hardware so they completely free to be used as GPIO. 19 | * 20 | * When the Wixel starts up, all the pins on Port 0 and Port 1 will be inputs with 21 | * internal pull-up resistors enabled except P1_0 and P1_1, which do not have 22 | * internal pull-up or pull-down resistors 23 | * 24 | * This library supports Port 2, but all of the Wixel's Port 2 pins are handled by the 25 | * functions declared in board.h so you should not need to manipulate them with this 26 | * library. 27 | * 28 | * \section pinparam The pinNumber parameter 29 | * 30 | * Most of the functions in this library take a pin number as their first 31 | * argument. These numbers are computed by multiplying the first digit in the 32 | * pin name by ten and adding it to the second digit, as shown in the table below. 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | *
CC2511 Pins
PinpinNumber parameter
P0_00
P0_11
P0_22
P0_33
P0_44
P0_55
P1_010
P1_111
P1_212
P1_313
P1_414
P1_515
P1_616
P1_717
P2_020
P2_121
P2_222
P2_323
P2_424\footnote
57 | * 58 | * \section interrupts Interrupts 59 | * 60 | * All the functions in this library are declared as reentrant, which means it is 61 | * safe to call them in your main loop and also in your interrupt service routines 62 | * (ISRs). 63 | * However, if you are using these functions in an ISR, you should make sure that you 64 | * have no code in your main loop that does a non-atomic read-modify-write operation 65 | * on any of the I/O registers that are changed in the interrupt. 66 | * The risk is that the interrupt could fire after while the read-modify-write 67 | * operation is in progress, after the register has been read but before it has been 68 | * written. Then when the register is written by the main loop, the change made by 69 | * the ISR will be unintentionally lost. 70 | * 71 | * For example, it would be bad if you called setDigitalOutput(10, 1) 72 | * in an interrupt and in your main loop you had some code like: 73 | \code 74 | P1DIR = (P1DIR & MASK) | VALUE; 75 | \endcode 76 | * 77 | * It is OK to have code like P1DIR |= VALUE; in your main loop because 78 | * that compiles to a single instruction, so it should be atomic. 79 | * 80 | * \section overhead Overhead 81 | * 82 | * Calling the functions in this library will be slower than manipulating the I/O 83 | * registers yourself, but the overhead should be roughly the same for each pin. 84 | * 85 | * This library (git revision 4de9ee1f) was tested with 86 | * SDCC 3.0.0 (#6037) and it was found that an I/O line could be toggled once 87 | * every 3.2 microseconds by calling setDigitalOutput() several times in a row. 88 | * 89 | * \section caveats Caveats 90 | * 91 | * To use your digital I/O pins correctly, there are several things you should be aware of: 92 | * - Maximum voltage ratings: Be sure to not expose your input pins to voltages 93 | * outside their allowed range. The voltage should not go below 0 V (GND) and should 94 | * not exceed VDD (typically 3.3 V). This means that you can not connect an input 95 | * on the CC2511 directly to an output from a 5V system if the output ever drives 96 | * high (5 V). You can use a voltage divider circuit, level-shifter, or diode to 97 | * overcome this limitation. 98 | * - Drawing too much current from an output pin: Be sure you do not attempt 99 | * to draw too much current from your output pin; it may break. 100 | * The amount of current that can be supplied by the CC2511's I/O pins is not 101 | * well-documented by the manufacturer. According to 102 | * this forum post by a TI Employee, 103 | * regular I/O pins are designed to be able to source 4 mA while P1_0 and P1_1 are designed for 20 mA. 104 | * You can use a transistor to overcome this limitation. 105 | * - Shorts: Be sure that you do not connect a high output pin directly to a 106 | * low output pin or to another high output pin that is driving to a different voltage. 107 | * - Peripheral functions: Many of the pins on the CC2511 can be configured to 108 | * be used by a peripheral by setting the right bit in the P0SEL, P1SEL, or P2SEL 109 | * register. When a pin is being used by a peripheral, the functions in this 110 | * library may not work. For example, if you have enabled USART1 in Alternate 111 | * Location 1, then you can not control the output value of P1_6 using these 112 | * functions because P1_6 serves as the serial transmit (TX) line. 113 | */ 114 | 115 | #ifndef _GPIO_H 116 | #define _GPIO_H 117 | 118 | #include 119 | 120 | /*! Represents a low voltage, also known as GND or 0 V. */ 121 | #define LOW 0 122 | 123 | /*! Represents a high voltage, also known as 3V3 (typically 3.3 V). */ 124 | #define HIGH 1 125 | 126 | /*! Specifies that the input pin should be a high-impedance input with no pull-up 127 | * or pull-down resistor enabled. See setDigitalInput(). */ 128 | #define HIGH_IMPEDANCE 0 129 | 130 | /*! Specifies that the pin should have a 20 kilohm pull-up or pull-down enabled. 131 | * See setDigitalInput(). */ 132 | #define PULLED 1 133 | 134 | /*! \brief Configures the specified pin as a digital output. 135 | \param pinNumber Should be one of the pin numbers listed in the table above (e.g. 12). 136 | \param value Should be one of the following: 137 | - #LOW (0): Drives the line low (GND, 0 V). 138 | - #HIGH (1): Drives the line high (3V3, typically 3.3 V). 139 | 140 | This function will not work if the pin has previously been configured as a 141 | peripheral function pin; the bit for this pin in P0SEL/P1SEL/P2SEL must be 0. 142 | 143 | This function first sets the output value, then it sets the pin direction. 144 | For example, calling setDigitalOutput(3, HIGH) will have the same effect as 145 | (but be slower than) this: 146 | 147 | \code 148 | P0_3 = 1; 149 | P0DIR |= (1<<3); 150 | \endcode */ 151 | void setDigitalOutput(uint8 pinNumber, BIT value) __reentrant; 152 | 153 | /*! \brief Configures the specified pin as an input. 154 | \param pinNumber Should be one of the pin numbers listed in the table above (e.g. 12). 155 | \param pulled Should be one of the following: 156 | - #HIGH_IMPEDANCE (0): Disables the internal pull-up and pull-down resistors on that pin. 157 | - #PULLED (1): Enables an internal 20 kilohm pull-up or pull-down resistor on the pin. 158 | The type of resistor used is set at the port level. By default, Port 0 and Port 1 159 | use pull-up resistors, but you can change those ports to use pull-down resistors 160 | calling setPort0PullType() or setPort1PullType(). You can not have pull-up and 161 | pull-down resistors enabled simultaneously for different pins on the same port. 162 | 163 | This function first sets the pull type, then it sets the pin direction. 164 | For example, calling setDigitalInput(15, PULLED) will have the same effect as 165 | (but be slower than) this: 166 | 167 | \code 168 | P1SEL &= ~(1<<5); 169 | P1DIR &= ~(1<<5); 170 | \endcode 171 | 172 | Note: The pins P1_0 and P1_1 do NOT have internal pull-up or pull-down resistors, 173 | so the second argument to this function does not have any effect when configuring 174 | either of those pins. 175 | 176 | */ 177 | void setDigitalInput(uint8 pinNumber, BIT pulled) __reentrant; 178 | 179 | /*! \brief Returns the current input or output value of the pin. 180 | * 181 | * \param pinNumber Should be one of the pin numbers listed in the table above (e.g. 12). 182 | * \return #LOW (0) or #HIGH (1). 183 | * 184 | * The return value represents a digital reading of the voltage on the pin. 185 | * According to the "DC Characteristics" section of the CC2511 datasheet, 186 | * voltages below 30% of VDD (typically 0.99 V on the Wixel) will read as 0, 187 | * while voltages above 70% of VDD (typically 2.31 V on the Wixel) 188 | * will read as 1. 189 | * 190 | * This function is intended to be used for pins that are configured as inputs. 191 | * For a pin configured as an output, it can be used, but it might sometimes 192 | * give unexpected results in case the current voltage has not 193 | * reached the voltage that the pin is configured to drive it to. 194 | * 195 | * This function simply returns the bit value of the port. For example, 196 | * calling isPinHigh(14) will have the effect as reading 197 | * P1_4 (but the function call will be slower). 198 | * */ 199 | BIT isPinHigh(uint8 pinNumber) __reentrant; 200 | 201 | /*! Selects whether Port 0 will have internal pull-down or pull-up resistors. 202 | * 203 | * \param pullType Specifies the voltage that the resistors will pull to. 204 | * Should be either #LOW (0) or #HIGH (1). 205 | * 206 | * The resistors can be disabled individually for each pin using setDigitalInput(), 207 | * but it is impossible to have pull-up and pull-down resistors enabled simultaneously 208 | * for different pins on the same port. 209 | */ 210 | void setPort0PullType(BIT pullType) __reentrant; 211 | 212 | /*! Same as setPort0PullType() except this function affects Port 1. */ 213 | void setPort1PullType(BIT pullType) __reentrant; 214 | 215 | /*! Same as setPort0PullType() except this function affects Port 2. 216 | * This function is included for the sake of completeness, but it should not 217 | * be used on a Wixel because all of the pins on Port 2 are managed by the 218 | * functions declared in board.h. */ 219 | void setPort2PullType(BIT pullType) __reentrant; 220 | 221 | #endif 222 | -------------------------------------------------------------------------------- /libraries/docs/overviews.dox: -------------------------------------------------------------------------------- 1 | /** \mainpage Wixel SDK Documentation 2 | 3 | The Pololu Wixel Software Development Kit (SDK) contains code and Makefiles 4 | that will help you create your own applications for the 5 | Pololu Wixel. 6 | The Wixel is a general-purpose programmable module featuring a 2.4 GHz radio 7 | and USB. 8 | The Wixel is based on the 9 | CC2511F32 10 | microcontroller from Texas Instruments, which has an integrated radio transceiver, 11 | 32 KB of flash memory, 4 KB of RAM, and a full-speed USB interface. 12 | 13 | \section starting Getting Started 14 | 15 | To load apps onto the Wixel, you will need to have 16 | the Wixel's drivers and software installed on your system. 17 | See the Getting Started section of the 18 | Pololu Wixel User's Guide. 19 | 20 | To develop your own apps or modify existing ones using the Wixel SDK, 21 | you will need to have a copy of the Wixel SDK, 22 | SDCC version 3.0.0 or later, 23 | and you will need to have certain GNU utililties available on your path: 24 | cat, cp, echo, grep, make, mv, rm, and sed. 25 | 26 | For Windows users, we recommend that you install all of these components 27 | by downloading the Wixel Development Bundle, available from the 28 | Pololu Wixel User's Guide. 29 | 30 | Please see the Writing Your Own Wixel App 31 | section of the 32 | Pololu Wixel User's Guide 33 | for step-by-step instructions for getting started with the Wixel SDK. 34 | 35 | \section sdk Downloading the Wixel SDK itself 36 | 37 | The Wixel SDK is available as a 38 | git repository hosted on github. 39 | You can get the latest version by installing git 40 | and running: 41 |
 42 | git clone -o pololu git://github.com/pololu/wixel-sdk.git
 43 | 
44 | 45 | If you need help, see github's instructions on how to 46 | Set Up Git. 47 | For Windows users, we also recommend installing 48 | TortoiseGit 49 | because it provides a good graphical user interface for git. 50 | 51 | You can also download the 52 | latest version of the Wixel SDK 53 | from github. 54 | 55 | 56 | \section building_app Building and Loading Apps 57 | 58 | Open a command-line terminal, navigate to the top level directory 59 | of the SDK, and type "make". This will build all of the apps in 60 | the apps folder and all of the libraries that they depend on. 61 | 62 | To load an app onto all the Wixels connected to the computer, 63 | type "make load_APPNAME" where APPNAME is the name of your app's 64 | folder in the apps directory. 65 | 66 | To open your app in the Wixel Configuration Utility, 67 | type "make open_APPNAME". 68 | 69 | Running any of the commands above will rebuild your app if it 70 | is out of date. 71 | 72 | \section creating_app Creating Your Own App 73 | 74 | To create your own app, simply copy one of the existing folders in the 75 | apps directory and change its name. 76 | You do not need to modify the Makefile; 77 | the Makefile will automatically detect the new app as long as it is in 78 | the apps folder. 79 | 80 | If your app doesn't use the default set of libraries defined in 81 | libraries/libs.mk, you can specify which libraries 82 | your app uses by creating a file called 83 | options.mk in your 84 | app directory and defining a GNU Make variable in it called APP_LIBS 85 | that contains a list of the file names of the libraries your app uses, separated 86 | by spaces. See apps/test_board/options.mk for an example. 87 | \endcode 88 | 89 | \section sdk_docs Documentation of Wixel SDK Libraries 90 | 91 | The Libraries page contains an overview 92 | of all the libraries available in this SDK. 93 | 94 | The File List page links to the documentation 95 | for all the library functions, grouped by header file. 96 | This documentation is auto-generated from the .h 97 | files in the SDK. 98 | 99 | The Globals page contains an index of all 100 | the global functions variables, typedefs, and defines in this SDK. 101 | 102 | To generate this documentation yourself, type "make docs" 103 | (requires Doxygen). 104 | 105 | \section other_docs Other Documentation 106 | 107 | Documentation for the Wixel itself is available in the 108 | Pololu Wixel User's Guide provided by Pololu. 109 | The user's guide contains schematic diagrams, pinout diagrams, documentation for the 110 | apps, example wiring, and more. 111 | 112 | Documentation for the CC2511F32 (the microcontroller on the Wixel) is available in the 113 | CC2511F32 datasheet 114 | provided by Texas Instruments. 115 | The datasheet provides detailed technical information about the hardware peripherals and 116 | how to control them, as well as electrical specifications, and more. 117 | Texas Instruments also provides many app notes and design notes on the 118 | CC2511 page. 119 | 120 | Documentation for SDCC is available on the SDCC website. 121 | 122 | \section make_exception Make Interrupt/Exception Error 123 | 124 | You might get the following error message from make in Windows: 125 |
126 | make: Interrupt/Exception caught (code = 0xc00000fd, addr = 0x425073)
127 | 
128 | 129 | If you get this error, please run "make -v" at a Command Prompt and make 130 | sure that you are running GNU Make 3.82-pololu1 or later. 131 | This version of make is included in the latest Wixel Development Bundle, 132 | available from the Pololu Wixel User's Guide. 133 | If the output from "make -v" shows some other version of make even after 134 | installing the Wixel Development Bundle, then you should remove that other version 135 | of make from your PATH or reorder your PATH so that version 3.82-pololu1 (or later) 136 | is used. 137 | You can edit your PATH environment variable from the Control Panel. 138 | See the pololu/make wiki on github 139 | for more information on this problem. 140 | 141 | \section help Getting Help 142 | 143 | If you have a problem or question, feel free to ask us on the 144 | Pololu Forum. 145 | 146 | 147 | **/ 148 | 149 | /******************************************************************************/ 150 | /** \defgroup libraries Wixel SDK Libraries 151 | 152 | \section radio_libs Radio Libraries 153 | 154 | - radio_com.lib (radio_com.h): Provides reliable, ordered 155 | delivery and reception of a stream of bytes between two devices. 156 | Also supports control signals. 157 | Depends on radio_link.lib. 158 | - radio_link.lib (radio_link.h): 159 | Provides reliable, ordered delivery and reception of a 160 | series of data packets between two devices. 161 | This is the layer that takes care of Ping/ACK/NAK packets, and handles the 162 | details of timing. Depends on radio_mac.lib. 163 | - radio_queue.lib (radio_queue.h): 164 | Provides queues for sending and receiving radio packets. 165 | It does not ensure reliability, nor does it specify a format for the 166 | packet contents. 167 | Depends on radio_mac.lib. 168 | - radio_mac.lib (radio_mac.h): Takes care of setting up the 169 | radio's DMA channel and interrupt, and allows higher-level code to control the 170 | radio from an interrupt. This is a general purpose library that could be used 171 | to implement any kind of radio protocol. 172 | Depends on radio_registers.lib and dma.lib. 173 | - radio_registers.lib (radio_registers.h): 174 | Configures the radio with some good default settings, and provides 175 | some basic functions for reading information from the radio. 176 | 177 | \section usb_libs USB Libraries 178 | 179 | - usb_cdc_acm.lib (usb_com.h): Implements the USB CDC ACM interface, which 180 | allows the Wixel to appear as a virtual COM port when it is connected to a PC. 181 | Depends on usb.lib and wixel.lib. 182 | - usb_hid.lib (usb_hid.h): Implements a USB Human Interface Device (HID) 183 | which allows the Wixel to appear as both a Mouse and Keyboard when it is 184 | connected to a PC. Depends on usb.lib and wixel.lib. 185 | - usb.lib (usb.h): Sets up the USB module and responds to standard device 186 | requests. This is a general purpose library that could be used to implement 187 | many different kinds of USB device interfaces. Depends on wixel.lib. 188 | 189 | \section peripheral_libs Peripheral Driver Libraries 190 | 191 | - adc.lib (adc.h): Uses the Analog-to-Digital Converter (ADC) to read analog voltages. 192 | - gpio.lib (gpio.h): Uses the CC2511's pins as general purpose inputs or outputs (GPIO). 193 | - i2c.lib (i2c.h): Provides a basic software (bit-banging) implementation of a master 194 | node for I2C communication. Depends on gpio.lib and wixel.lib. 195 | - servo.lib (servo.h): Provides the ability to control up to 6 196 | RC servos by generating digital pulses directly from your Wixel without the 197 | need for a separate servo controller. 198 | - uart.lib (uart0.h, uart1.h): Uses USART0 and/or USART1 in UART mode to send and 199 | receive serial bytes. 200 | - spi_master.lib (spi0_master.h, spi1_master.h): Uses USART0 and/or USART1 in SPI mode to send and receive bytes from an SPI slave. 201 | 202 | \section basic_libs Basic Libraries 203 | 204 | - wixel.lib (board.h, time.h): Takes care of everything that is specific 205 | to the Wixel hardware, including managing LEDs and other I/O lines, detecting 206 | the current power source, keeping track of time, and providing delay 207 | functions. 208 | - dma.lib (dma.h): Coordinates the use of DMA channels 1-3. Does not touch DMA channel 0. 209 | - random.lib (random.h): Takes care of generating random numbers. 210 | 211 | \section libc Standard C Libraries 212 | 213 | The Small Device C Compiler (SDCC) provides library routines that may be 214 | useful for your application. In particular, if you need to format a string of 215 | ASCII text, sprintf is useful. SDCC also provides math routines 216 | and a memory allocation routine (malloc). 217 | See the 218 | Library 219 | Routines section of the SDCC manual for more information. 220 | Also, several of the example and test apps in the apps directory 221 | use printf or sprintf. 222 | 223 | **/ 224 | --------------------------------------------------------------------------------