/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See the file COPYING * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Copyright (C) 2010 Frank van Maarseveen */ #include #include #include "common.h" #include "bits.h" #include "timer0.h" #include "hardware.h" #include "udelay.h" #include "serial.h" /* * ISRs can take significant time (say 100 us in a worst case scenario) so * lets pick a safe but a little bit slow baudrate. Note that t0_ticks() has * 16us resolution and wraps roughly every 4ms. Less than 600 baud becomes * visible for the eye so... */ //#define BAUDRATE 75 /* 827 ticks */ //#define BAUDRATE 1200 /* 0.833 ms (actual: 52 ticks, 0.832 ms) */ //#define BAUDRATE 600 /* 1.667 ms (actual: 103 ticks, 1.648 ms) */ #define BAUDRATE 2400 #define T_US ((1000000 + BAUDRATE / 2) / BAUDRATE) #define T_TICKS ((T_US * T0_MS + 500) / 1000) #define LOOP_US (12/MHZ) /* estimated loop overhead in us */ /* * A low T_TICKS is not a problem on its own because timer wait functions wait for * a transition, making the start-bit synchronize. However, rounding errors * in calculating T_TICKS and latency caused by ISRs are a problem. So, choose an * implementation depending on T_TICKS. */ #if T_TICKS > 8 /* <= 6944 baud. T_TICKS==13 yields 4808 baud */ /* * When T_TICKS is close to 127 ticks or higher then use an additional loop. */ #define TMIN 2 #define TMAX 110 #define ITERATIONS (((T_TICKS) - TMIN) / TMAX) #define REMAINDER (((T_TICKS) - TMIN) % TMAX + TMIN) __attribute__((noinline)) static uint8_t wait_clock_cycle(uint8_t t) { uint8_t i; for (i = 0; i < ITERATIONS; ++i) { t += TMAX; t0_tickwait_until(t); } t += REMAINDER; t0_tickwait_until(t); return t; } /* * idle start stop start stop idle * | | | | * V V V V * ________ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ________ * |_|_|_|_|_|_|_|_|_| |_|_|_|_|_|_|_|_|_| * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 * * RS-232 * state voltage bit LED * mark -5..-15 1 off * space +5..+15 0 on */ void ser_tx(uint8_t byte) { uint8_t t, i; t = t0_ticks(0); CLR(LED); t = wait_clock_cycle(t); SET(LED); /* startbit (0) */ t = wait_clock_cycle(t); for (i = 0; i < 8; ++i) { if (byte & 1) CLR(LED); else SET(LED); byte >>= 1; t = wait_clock_cycle(t); } CLR(LED); /* stopbit (1) */ t = wait_clock_cycle(t); } #elif T_US <= 255 && T_US > 8 && T_US > LOOP_US /* ..115200 baud (111111 actually) */ /* * Interrupts are off for 9*T_US! (938 us at 9600 baud) */ void ser_tx(uint8_t byte) { uint8_t i, sreg; saveicli(sreg); CLR(LED); udelay(T_US); SET(LED); udelay(T_US); for (i = 0; i < 8; ++i) { if (byte & 1) CLR(LED); else SET(LED); byte >>= 1; udelay(T_US - LOOP_US); } CLR(LED); restorei(sreg); udelay(T_US); } #endif