From: Mikko Rasa Date: Wed, 23 Oct 2013 21:36:44 +0000 (+0300) Subject: Add support for S88 feedback modules X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=3bbca0dcce53ff9e2cdaa3d39ae18afcbf627f9d;p=model-railway-devices.git Add support for S88 feedback modules --- diff --git a/arducontrol/Makefile b/arducontrol/Makefile index b520eb7..a7cb562 100644 --- a/arducontrol/Makefile +++ b/arducontrol/Makefile @@ -1,3 +1,3 @@ include ../common/build.mk -arducontrol.elf: adc.o interface.o monitor.o motorola.o output.o serial.o timer.o +arducontrol.elf: adc.o interface.o monitor.o motorola.o output.o serial.o s88.o timer.o diff --git a/arducontrol/arducontrol.c b/arducontrol/arducontrol.c index 1c8cde9..8ec27ea 100644 --- a/arducontrol/arducontrol.c +++ b/arducontrol/arducontrol.c @@ -11,6 +11,12 @@ Connections for Pololu high-powered motor driver: D2 <-> DIR D3 <-> PWM +Connections for S88 bus: +D4 <-> RESET +D5 <-> LOAD +D6 <-> CLOCK +D7 <-> DATA + ADC connections: ADC0 - current sensor (adjusted for 185 mV/A, centered at Vcc/2) ADC1 - input voltage (adjusted for divisor of 11) @@ -38,12 +44,14 @@ its data to the track can start. #include "interface.h" #include "monitor.h" #include "output.h" +#include "s88.h" int main(void) { output_init(); interface_init(); monitor_init(); + s88_init(); sei(); @@ -51,6 +59,7 @@ int main(void) { interface_check(); monitor_check(); + s88_check(); } return 0; diff --git a/arducontrol/commands.h b/arducontrol/commands.h index 865405d..eae919c 100644 --- a/arducontrol/commands.h +++ b/arducontrol/commands.h @@ -13,6 +13,7 @@ enum Command MOTOROLA_SPEED_DIRECTION = 0x13, MOTOROLA_SPEED_FUNCTION = 0x14, MOTOROLA_SOLENOID = 0x15, + S88_READ = 0x30, COMMAND_OK = 0x80, RECEIVE_OVERRUN = 0x81, FRAMING_ERROR = 0x82, @@ -21,7 +22,8 @@ enum Command INVALID_VALUE = 0x85, OVERCURRENT = 0xA0, TRACK_CURRENT = 0xC0, - INPUT_VOLTAGE = 0xC1 + INPUT_VOLTAGE = 0xC1, + S88_DATA = 0xD0 }; #endif diff --git a/arducontrol/interface.c b/arducontrol/interface.c index 96baba7..4064120 100644 --- a/arducontrol/interface.c +++ b/arducontrol/interface.c @@ -3,6 +3,7 @@ #include "motorola.h" #include "output.h" #include "serial.h" +#include "s88.h" volatile uint8_t recv_buf[32]; uint8_t recv_head = 0; @@ -83,6 +84,8 @@ uint8_t dispatch_command(const uint8_t *cmd, uint8_t length) } else if(type==1) return motorola_command(cmd, length); + else if(type==3) + return s88_command(cmd, length); else return INVALID_COMMAND; } diff --git a/arducontrol/s88.c b/arducontrol/s88.c new file mode 100644 index 0000000..1ce5740 --- /dev/null +++ b/arducontrol/s88.c @@ -0,0 +1,110 @@ +#include +#include "interface.h" +#include "ringbuffer.h" +#include "s88.h" +#include "serial.h" +#include "timer.h" + +#define RESET PORTD4 +#define LOAD PORTD5 +#define CLOCK PORTD6 +#define DATA PIN7 +#define BIT(x) (1<<(x)) + +volatile uint8_t s88_read_count = 0; +uint8_t s88_read_bit = 0; +volatile uint8_t s88_read_phase = 0; +uint8_t s88_data = 0; +RINGBUFFER(s88_buffer, 8); +uint8_t s88_out_index = 0; + +void s88_init(void) +{ + DDRD = (DDRD&0x0F)|0x70; + PORTD &= 0x0F; + + timer_start_hz(0, 80000, 1); +} + +void s88_check(void) +{ + // Only send one packet per check to avoid blocking + if(ringbuffer_fill(s88_buffer)>0) + { + uint8_t reply[3]; + reply[0] = S88_DATA; + reply[1] = s88_out_index++; + reply[2] = ringbuffer_pop(s88_buffer); + interface_send(reply, sizeof(reply)); + } +} + +uint8_t s88_command(const uint8_t *cmd_buf, uint8_t cmd_length) +{ + if(cmd_buf[0]==S88_READ) + { + if(cmd_length!=2) + return LENGTH_ERROR; + + while(s88_read_count || s88_read_phase) ; + + s88_out_index = 0; + s88_read_phase = 0xF0; + s88_read_count = cmd_buf[1]; + } + else + return INVALID_COMMAND; + + return COMMAND_OK; +} + +static inline void s88_tick(void) +{ + if(s88_read_phase==0) + { + if(!s88_read_count || ringbuffer_space(s88_buffer)==0) + return; + + PORTD |= BIT(CLOCK); + } + else if(s88_read_phase==1) + { + uint8_t bit = (PIND>>7)&1; + s88_data = (s88_data<<1)|bit; + ++s88_read_bit; + if(s88_read_bit==8) + { + ringbuffer_push(s88_buffer, s88_data); + + --s88_read_count; + s88_read_bit = 0; + } + } + else if(s88_read_phase==2) + PORTD &= ~BIT(CLOCK); + else if(s88_read_phase>3) + { + if(s88_read_phase==0xF0) + PORTD |= BIT(LOAD); + else if(s88_read_phase==0xF4) + PORTD |= BIT(CLOCK); + else if(s88_read_phase==0xF6) + PORTD &= ~BIT(CLOCK); + else if(s88_read_phase==0xFA) + PORTD |= BIT(RESET); + else if(s88_read_phase==0xFC) + PORTD &= ~BIT(RESET); + else if(s88_read_phase==0xFF) + { + s88_data = (PIND>>7)&1; + ++s88_read_bit; + PORTD &= ~BIT(LOAD); + } + ++s88_read_phase; + return; + } + + s88_read_phase = (s88_read_phase+1)&3; +} + +TIMER_SET_CALLBACK(0, s88_tick) diff --git a/arducontrol/s88.h b/arducontrol/s88.h new file mode 100644 index 0000000..b440ebe --- /dev/null +++ b/arducontrol/s88.h @@ -0,0 +1,10 @@ +#ifndef S88_H_ +#define S88_H_ + +#include + +void s88_init(void); +void s88_check(void); +uint8_t s88_command(const uint8_t *, uint8_t); + +#endif