PageRenderTime 29ms CodeModel.GetById 12ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/firmware/src/shared/UART.cc

http://github.com/makerbot/G3Firmware
C++ | 292 lines | 208 code | 50 blank | 34 comment | 46 complexity | da411007c39178d5a833a51b4d9f7c3a MD5 | raw file
  1/*
  2 * Copyright 2010 by Adam Mayer	 <adam@makerbot.com>
  3 *
  4 * This program is free software: you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation, either version 3 of the License, or
  7 * (at your option) any later version.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 16 */
 17
 18
 19#include "UART.hh"
 20#include "Pin.hh"
 21#include <stdint.h>
 22#include <avr/sfr_defs.h>
 23#include <avr/interrupt.h>
 24#include <avr/io.h>
 25#include <util/delay.h>
 26#include <avr/io.h>
 27
 28
 29// TODO: There should be a better way to enable this flag?
 30#if ASSERT_LINE_FIX
 31#include "ExtruderBoard.hh"
 32#endif
 33
 34// We have to track the number of bytes that have been sent, so that we can filter
 35// them from our receive buffer later.This is only used for RS485 mode.
 36volatile uint8_t loopback_bytes = 0;
 37
 38// We support three platforms: Atmega168 (1 UART), Atmega644, and Atmega1280/2560
 39#if defined (__AVR_ATmega168__)     \
 40    || defined (__AVR_ATmega328P__)  \
 41    || defined (__AVR_ATmega644P__) \
 42    || defined (__AVR_ATmega1280__) \
 43    || defined (__AVR_ATmega2560__)
 44#else
 45    #error UART not implemented on this processor type!
 46#endif
 47
 48#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
 49
 50    #define UBRR_VALUE 25
 51    #define UCSR0A_VALUE 0
 52
 53    #define INIT_SERIAL(uart_) \
 54    { \
 55        UBRR0H = UBRR_VALUE >> 8; \
 56        UBRR0L = UBRR_VALUE & 0xff; \
 57        \
 58        /* set config for uart, explicitly clear TX interrupt flag */ \
 59        UCSR0A = UCSR0A_VALUE | _BV(TXC0); \
 60        UCSR0B = _BV(RXEN0) | _BV(TXEN0); \
 61        UCSR0C = _BV(UCSZ01)|_BV(UCSZ00); \
 62    }
 63
 64#elif defined (__AVR_ATmega644P__)
 65
 66    #define UBRR_VALUE 25
 67    #define UBRRA_VALUE 0
 68
 69    // Adapted from ancient arduino/wiring rabbit hole
 70    #define INIT_SERIAL(uart_) \
 71    { \
 72        UBRR##uart_##H = UBRR_VALUE >> 8; \
 73        UBRR##uart_##L = UBRR_VALUE & 0xff; \
 74        \
 75        /* set config for uart_ */ \
 76        UCSR##uart_##A = UBRRA_VALUE; \
 77        UCSR##uart_##B = _BV(RXEN##uart_) | _BV(TXEN##uart_); \
 78        UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
 79    }
 80
 81#elif defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
 82
 83    // Use double-speed mode for more accurate baud rate?
 84    #define UBRR0_VALUE 16 // 115200 baud
 85    #define UBRR1_VALUE 51 // 38400 baud
 86    #define UCSRA_VALUE(uart_) _BV(U2X##uart_)
 87
 88    // Adapted from ancient arduino/wiring rabbit hole
 89    #define INIT_SERIAL(uart_) \
 90    { \
 91        UBRR##uart_##H = UBRR##uart_##_VALUE >> 8; \
 92        UBRR##uart_##L = UBRR##uart_##_VALUE & 0xff; \
 93        \
 94        /* set config for uart_ */ \
 95        UCSR##uart_##A = UCSRA_VALUE(uart_); \
 96        UCSR##uart_##B = _BV(RXEN##uart_) | _BV(TXEN##uart_); \
 97        UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
 98    }
 99#endif
100
101#define ENABLE_SERIAL_INTERRUPTS(uart_) \
102{ \
103UCSR##uart_##B |= _BV(RXCIE##uart_) | _BV(TXCIE##uart_); \
104}
105
106#define DISABLE_SERIAL_INTERRUPTS(uart_) \
107{ \
108UCSR##uart_##B &= ~(_BV(RXCIE##uart_) | _BV(TXCIE##uart_)); \
109}
110
111// TODO: Move these definitions to the board files, where they belong.
112#if defined (__AVR_ATmega168__) \
113    || defined (__AVR_ATmega328P__)
114
115    UART UART::hostUART(0, RS485);
116
117#elif defined (__AVR_ATmega644P__) \
118    || defined (__AVR_ATmega1280__) \
119    || defined (__AVR_ATmega2560__)
120
121    UART UART::hostUART(0, RS232);
122
123    #if HAS_SLAVE_UART
124        UART UART::slaveUART(1, RS485);
125    #endif
126
127#endif
128
129
130void UART::init_serial() {
131    if(index_ == 0) {
132        INIT_SERIAL(0);
133    }
134#if HAS_SLAVE_UART
135    else {
136        INIT_SERIAL(1);
137    }
138#endif
139}
140
141void UART::send_byte(char data) {
142    if(index_ == 0) {
143        UDR0 = data;
144    }
145#if HAS_SLAVE_UART
146    else {
147        UDR1 = data;
148    }
149#endif
150}
151
152// Transition to a non-transmitting state. This is only used for RS485 mode.
153inline void listen() {
154//        TX_ENABLE_PIN.setValue(false);
155    TX_ENABLE_PIN.setValue(false);
156}
157
158// Transition to a transmitting state
159inline void speak() {
160    TX_ENABLE_PIN.setValue(true);
161}
162
163UART::UART(uint8_t index, communication_mode mode) :
164    index_(index),
165    mode_(mode),
166    enabled_(false) {
167
168        init_serial();
169
170}
171
172// Subsequent bytes will be triggered by the tx complete interrupt.
173void UART::beginSend() {
174        if (!enabled_) { return; }
175
176        if (mode_ == RS485) {
177                speak();
178                _delay_us(10);
179                loopback_bytes = 1;
180        }
181
182        send_byte(out.getNextByteToSend());
183}
184
185void UART::enable(bool enabled) {
186        enabled_ = enabled;
187        if (index_ == 0) {
188                if (enabled) { ENABLE_SERIAL_INTERRUPTS(0); }
189                else { DISABLE_SERIAL_INTERRUPTS(0); }
190        }
191#if HAS_SLAVE_UART
192        else if (index_ == 1) {
193                if (enabled) { ENABLE_SERIAL_INTERRUPTS(1); }
194                else { DISABLE_SERIAL_INTERRUPTS(1); }
195        }
196#endif
197
198        if (mode_ == RS485) {
199                // If this is an RS485 pin, set up the RX and TX enable control lines.
200                TX_ENABLE_PIN.setDirection(true);
201                RX_ENABLE_PIN.setDirection(true);
202                RX_ENABLE_PIN.setValue(false);  // Active low
203                listen();
204
205                loopback_bytes = 0;
206        }
207}
208
209// Reset the UART to a listening state.  This is important for
210// RS485-based comms.
211void UART::reset() {
212        if (mode_ == RS485) {
213                loopback_bytes = 0;
214                listen();
215        }
216}
217
218#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
219
220    // Send and receive interrupts
221    ISR(USART_RX_vect)
222    {
223            static uint8_t byte_in;
224
225            byte_in = UDR0;
226            if (loopback_bytes > 0) {
227                    loopback_bytes--;
228            } else {
229                    UART::getHostUART().in.processByte( byte_in );
230
231                    // Workaround for buggy hardware: have slave hold line high.
232    #if ASSERT_LINE_FIX
233                    if (UART::getHostUART().in.isFinished()
234                            && (UART::getHostUART().in.read8(0)
235                            == ExtruderBoard::getBoard().getSlaveID())) {
236                        speak();
237                    }
238    #endif
239            }
240    }
241
242    ISR(USART_TX_vect)
243    {
244            if (UART::getHostUART().out.isSending()) {
245                    loopback_bytes++;
246                    UDR0 = UART::getHostUART().out.getNextByteToSend();
247            } else {
248                    listen();
249            }
250    }
251
252#elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
253
254    // Send and receive interrupts
255    ISR(USART0_RX_vect)
256    {
257            UART::getHostUART().in.processByte( UDR0 );
258    }
259
260    ISR(USART0_TX_vect)
261    {
262            if (UART::getHostUART().out.isSending()) {
263                    UDR0 = UART::getHostUART().out.getNextByteToSend();
264            }
265    }
266
267    #if HAS_SLAVE_UART
268        ISR(USART1_RX_vect)
269        {
270                static uint8_t byte_in;
271
272                byte_in = UDR1;
273                if (loopback_bytes > 0) {
274                        loopback_bytes--;
275                } else {
276                        UART::getSlaveUART().in.processByte( byte_in );
277                }
278        }
279
280        ISR(USART1_TX_vect)
281        {
282                if (UART::getSlaveUART().out.isSending()) {
283                        loopback_bytes++;
284                        UDR1 = UART::getSlaveUART().out.getNextByteToSend();
285                } else {
286                        _delay_us(10);
287                        listen();
288                }
289        }
290    #endif
291
292#endif