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 |