git-svn-id: https://bucket.mit.edu/svn/nilm/zoom@4367 ddd99763-3ecb-0310-9145-efcb8ce7c51ftags/zoom-1.0
@@ -0,0 +1,13 @@ | |||||
sources = main.c serial.c isr.c dac.c | |||||
dest = main.hex | |||||
# Default rule: build dest, plus assembly for all source | |||||
all: $(dest) $(sources:.c=.as) | |||||
# Destination is built from all object files | |||||
$(dest) : $(sources:.c=.obj) | |||||
burn: $(dest) | |||||
jimpic -b $< | |||||
include Makefile.pic |
@@ -0,0 +1,33 @@ | |||||
PICCFLAGS ?= -16f627a -DPIC -O -Zg | |||||
PICLDFLAGS ?= -16f627a | |||||
PICC ?= picl | |||||
%.d: %.c | |||||
$(SHELL) -ec '$(CC) -MM $(CPPFLAGS) $< \ | |||||
| sed '\''s/\($*\)\.o[ :]*/\1.obj $@ : /g'\'' > $@; \ | |||||
[ -s $@ ] || rm -f $@' | |||||
include $(sources:.c=.d) | |||||
.PHONY: clean burn | |||||
clean: | |||||
rm -f *.{d*,o,obj,sym,lst,map,cod,cof,dep,hex,as,rlf} *~ | |||||
%.lst %.hex : %.asm | |||||
gpasm $< | |||||
%.as : %.c | |||||
cd $(dir $<) && $(PICC) $(PICCFLAGS) -S -c $(notdir $<) | |||||
%.o : %.asm | |||||
gpasm -c $< | |||||
%.o : %.pal | |||||
gpal -t -c $< | |||||
%.obj : %.c | |||||
cd $(dir $<) && $(PICC) $(PICCFLAGS) -c $(notdir $<) | |||||
%.hex : %.obj | |||||
$(PICC) $(PICLDFLAGS) -O$@ -o $^ |
@@ -0,0 +1,45 @@ | |||||
#ifndef CONFIG_H | |||||
#define CONFIG_H | |||||
#define CONFIGWORD (WDTDIS & PWRTEN & MCLREN & BOREN & LVPEN & HS) | |||||
#define FOSC 4000000 | |||||
/* Max standard baudrate with FOSC=4000000 is 19200 */ | |||||
/* Max standard baudrate with FOSC=18432000 is 230400 */ | |||||
/* Max standard baudrate with FOSC=20000000 is 115200 */ | |||||
#define BAUDRATE 9600L | |||||
typedef unsigned char uint8_t; | |||||
typedef signed char sint8_t; | |||||
typedef unsigned int uint16_t; | |||||
typedef signed int sint16_t; | |||||
typedef unsigned long uint32_t; | |||||
typedef signed long uint32_t; | |||||
/* Serial */ | |||||
#define RX RB1 | |||||
#define TRISRX TRISB1 | |||||
#define TX RB2 | |||||
#define TRISTX TRISB2 | |||||
/* DAC */ | |||||
#define D15 RB7 | |||||
#define D14 RB6 | |||||
#define D13 RB5 | |||||
#define D12 RB3 | |||||
#define D11 RA3 | |||||
#define D10 RA2 | |||||
#define D9 RA1 | |||||
#define D8 RA0 | |||||
#define LDAC RB0 | |||||
#define TRIS_D15 TRISB7 | |||||
#define TRIS_D14 TRISB6 | |||||
#define TRIS_D13 TRISB5 | |||||
#define TRIS_D12 TRISB3 | |||||
#define TRIS_D11 TRISA3 | |||||
#define TRIS_D10 TRISA2 | |||||
#define TRIS_D9 TRISA1 | |||||
#define TRIS_D8 TRISA0 | |||||
#define TRIS_LDAC TRISB0 | |||||
#endif |
@@ -0,0 +1,33 @@ | |||||
#include <pic.h> | |||||
#include "config.h" | |||||
#include "dac.h" | |||||
/* Initialize dac */ | |||||
void dac_init(void) | |||||
{ | |||||
TRIS_D15 = 0; | |||||
TRIS_D14 = 0; | |||||
TRIS_D13 = 0; | |||||
TRIS_D12 = 0; | |||||
TRIS_D11 = 0; | |||||
TRIS_D10 = 0; | |||||
TRIS_D9 = 0; | |||||
TRIS_D8 = 0; | |||||
TRIS_LDAC = 0; | |||||
LDAC = 1; | |||||
} | |||||
/* Write value to dac */ | |||||
void dac_set(uint8_t val) | |||||
{ | |||||
D15 = 0; if (val & (1 << 7)) D15 = 1; | |||||
D14 = 0; if (val & (1 << 6)) D14 = 1; | |||||
D13 = 0; if (val & (1 << 5)) D13 = 1; | |||||
D12 = 0; if (val & (1 << 4)) D12 = 1; | |||||
D11 = 0; if (val & (1 << 3)) D11 = 1; | |||||
D10 = 0; if (val & (1 << 2)) D10 = 1; | |||||
D9 = 0; if (val & (1 << 1)) D9 = 1; | |||||
D8 = 0; if (val & (1 << 0)) D8 = 1; | |||||
LDAC = 0; | |||||
LDAC = 1; | |||||
} |
@@ -0,0 +1,9 @@ | |||||
#ifndef DAC_H | |||||
#define DAC_H | |||||
#include "config.h" | |||||
void dac_init(void); | |||||
void dac_set(uint8_t val); | |||||
#endif |
@@ -0,0 +1,13 @@ | |||||
#include <pic.h> | |||||
#include "config.h" | |||||
#include "isr.h" | |||||
#include "serial.h" | |||||
#pragma interrupt_level 1 | |||||
void interrupt isr(void) | |||||
{ | |||||
if(TXIE && TXIF) | |||||
serial_interrupt_tx(); | |||||
if(RCIE && RCIF) | |||||
serial_interrupt_rx(); | |||||
} |
@@ -0,0 +1,6 @@ | |||||
#ifndef ISR_H | |||||
#define ISR_H | |||||
void interrupt isr(void); | |||||
#endif |
@@ -0,0 +1,18 @@ | |||||
#include <pic.h> | |||||
#include "config.h" | |||||
#include "serial.h" | |||||
#include "dac.h" | |||||
__CONFIG(CONFIGWORD); | |||||
void main(void) { | |||||
CMCON = 7; | |||||
serial_init(); | |||||
dac_init(); | |||||
while(1) | |||||
{ | |||||
dac_set(serial_get()); | |||||
} | |||||
} |
@@ -0,0 +1,156 @@ | |||||
#include <pic.h> | |||||
#include "config.h" | |||||
#include "serial.h" | |||||
volatile uint8_t stq[STQ_SIZE], stq_start, stq_len; | |||||
volatile uint8_t bank1 srq[SRQ_SIZE], srq_start, srq_len; | |||||
/* | |||||
* Initialization | |||||
*/ | |||||
void serial_init(void) | |||||
{ | |||||
/* Set up serial transmit queue and serial receive queue */ | |||||
stq_start = stq_len = 0; | |||||
srq_start = srq_len = 0; | |||||
/* Initialize serial port with baudrate specified in config.h */ | |||||
TRISRX = 1; | |||||
TRISTX = 1; | |||||
BRGH = 1; | |||||
#define BRG (((FOSC + (8 * BAUDRATE - 1)) /(16 * BAUDRATE)) - 1) | |||||
#if (BRG < 1) || (BRG > 255) | |||||
#error Cannot achieve baudrate | |||||
#endif | |||||
#define ACT_BR (FOSC / (16 * (BRG + 1))) | |||||
#if ((ACT_BR * 100 / BAUDRATE) > 105) || ((ACT_BR * 100 / BAUDRATE) < 94) | |||||
#error Actual baudrate is too far from requested baudrate. Ratio is | |||||
#error FOSC/(16*floor((FOSC+(8*BAUDRATE-1))/(16*BAUDRATE)))/BAUDRATE | |||||
#endif | |||||
SPBRG = BRG; | |||||
SYNC = 0; | |||||
SPEN = 1; | |||||
CREN = 1; | |||||
SREN = 0; | |||||
TX9 = 0; | |||||
RX9 = 0; | |||||
TXEN = 1; | |||||
/* Enable serial port interrupts. To avoid being interrupted | |||||
all the time, TXIE is kept off until we have data to | |||||
transmit. */ | |||||
TXIE = 0; | |||||
RCIE = 1; | |||||
PEIE = 1; | |||||
} | |||||
/* | |||||
* Interrupt handling | |||||
*/ | |||||
/* Get a byte from the transmit queue and send it */ | |||||
void serial_interrupt_tx(void) | |||||
{ | |||||
if(stq_len != 0) { | |||||
TXREG = stq[stq_start]; | |||||
stq_start = (stq_start + 1) & STQ_MASK; | |||||
stq_len--; | |||||
} | |||||
/* If queue is empty, disable interrupt */ | |||||
if(stq_len == 0) | |||||
TXIE = 0; | |||||
} | |||||
/* Receive a byte and write it to the receive queue. */ | |||||
void serial_interrupt_rx(void) | |||||
{ | |||||
if(FERR) { | |||||
/* Framing error: discard byte */ | |||||
(void) RCREG; | |||||
return; | |||||
} | |||||
if(OERR) { | |||||
/* Overflow error, clear it */ | |||||
CREN = 0; | |||||
CREN = 1; | |||||
return; | |||||
} | |||||
if(!(srq_len & SRQ_SIZE)) { | |||||
srq[(srq_start + srq_len) & SRQ_MASK] = RCREG; | |||||
srq_len++; | |||||
} else { | |||||
/* Queue is full; discard data */ | |||||
(void) RCREG; | |||||
} | |||||
} | |||||
/* | |||||
* Userspace interface | |||||
*/ | |||||
/* Send byte to PC. Blocks iff transmit queue is full. */ | |||||
void serial_put(uint8_t x) | |||||
{ | |||||
while(!serial_can_put()) | |||||
continue; | |||||
GIE = 0; | |||||
stq[(stq_start + stq_len) & STQ_MASK] = x; | |||||
stq_len++; | |||||
TXIE = 1; | |||||
GIE = 1; | |||||
} | |||||
/* Get byte from PC. Blocks iff receive queue is empty. */ | |||||
uint8_t serial_get(void) | |||||
{ | |||||
uint8_t x; | |||||
while(!serial_can_get()) | |||||
continue; | |||||
x = srq[srq_start]; | |||||
GIE = 0; | |||||
srq_start = (srq_start + 1) & SRQ_MASK; | |||||
srq_len--; | |||||
GIE = 1; | |||||
return x; | |||||
} | |||||
/* | |||||
* I/O helpers | |||||
*/ | |||||
void serial_put_string(const uint8_t *s) | |||||
{ | |||||
while(s && *s) | |||||
serial_put(*s++); | |||||
} | |||||
const uint8_t hex[16]={'0','1','2','3','4','5','6','7', | |||||
'8','9','a','b','c','d','e','f'}; | |||||
void serial_put_hex(uint8_t x) | |||||
{ | |||||
serial_put(hex[x >> 4]); | |||||
serial_put(hex[x & 15]); | |||||
} | |||||
void serial_put_hex32(uint32_t x) | |||||
{ | |||||
serial_put_hex((x >> 24) & 0xFF); | |||||
serial_put_hex((x >> 16) & 0xFF); | |||||
serial_put_hex((x >> 8) & 0xFF); | |||||
serial_put_hex((x) & 0xFF); | |||||
} | |||||
void serial_crlf(void) | |||||
{ | |||||
serial_put('\r'); | |||||
serial_put('\n'); | |||||
} |
@@ -0,0 +1,43 @@ | |||||
#ifndef SERIAL_H | |||||
#define SERIAL_H | |||||
/* These serial port routines use both transmit and receive queues. | |||||
The actual sending/receiving is handled by the serial_interrupt | |||||
functions, which should get called on TXIF or RCIF. */ | |||||
#include "config.h" | |||||
#define STQ_BITS 6 /* transmit queue */ | |||||
#define SRQ_BITS 6 /* receive queue */ | |||||
#define STQ_SIZE (1<<(STQ_BITS)) | |||||
#define SRQ_SIZE (1<<(SRQ_BITS)) | |||||
#define STQ_MASK (STQ_SIZE-1) | |||||
#define SRQ_MASK (SRQ_SIZE-1) | |||||
extern volatile uint8_t stq[STQ_SIZE], stq_start, stq_len; | |||||
extern volatile bank1 uint8_t srq[SRQ_SIZE], srq_start, srq_len; | |||||
/* Initialize serial port, queues, serial interrupt */ | |||||
void serial_init(void); | |||||
/* Call this on (TXIE && TXIF) and (RCIE && RCIF), respectively */ | |||||
void serial_interrupt_tx(void); | |||||
void serial_interrupt_rx(void); | |||||
/* Send byte to PC. Blocks iff transmit queue is full. */ | |||||
void serial_put(uint8_t x); | |||||
/* Helper functions */ | |||||
void serial_put_string(const uint8_t *s); | |||||
void serial_crlf(void); | |||||
void serial_put_hex(uint8_t x); | |||||
void serial_put_hex32(uint32_t x); | |||||
/* Get byte from PC. Blocks iff receive queue is empty. */ | |||||
uint8_t serial_get(void); | |||||
/* Returns true if the respective get/put operation would not block */ | |||||
#define serial_can_get() (srq_len != 0) | |||||
#define serial_can_put() (!(stq_len & STQ_SIZE)) | |||||
#endif |