1 | //! -----------------------------------------------------------------------------------------------
|
2 | //!
|
3 | //! © Copyright 2011 by
|
4 | //!
|
5 | //! Carsten Wille
|
6 | //! Karlstraße 68
|
7 | //! D-38106 Braunschweig
|
8 | //!
|
9 | //! All rights reserved.
|
10 | //!
|
11 | //! Redistribution and use in source and binary forms, with or without modification, are permitted
|
12 | //! provided that the following conditions are met:
|
13 | //!
|
14 | //! * Redistributions of source code must retain the above copyright notice, this list of
|
15 | //! conditions and the following disclaimer.
|
16 | //! * Redistributions in binary form must reproduce the above copyright notice, this list of
|
17 | //! conditions and the following disclaimer in the documentation and/or other materials provided
|
18 | //! with the distribution.
|
19 | //! * Neither the name of Carsten Wille nor the names of its contributors may be used to
|
20 | //! endorse or promote products derived from this software without specific prior written
|
21 | //! permission.
|
22 | //!
|
23 | //! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
24 | //! IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
25 | //! AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
26 | //! CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27 | //! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
28 | //! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
29 | //! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
30 | //! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
31 | //! POSSIBILITY OF SUCH DAMAGE.
|
32 | //!
|
33 | //! -----------------------------------------------------------------------------------------------
|
34 |
|
35 | // Make the necessary adjustments at this point to match with the desired target MCU and clocking.
|
36 | #define F_CPU 32000000UL // Run with 32MHz after PLL
|
37 | #define USARTxx USARTC1 // Choose USART C1 as communications port
|
38 | #define USARTport PORTC // Matching port for the chosen USART
|
39 | #define USARTtxd PIN7_bm // Bit mask of the TxD pin
|
40 |
|
41 | #include <avr/eeprom.h>
|
42 | #include <avr/interrupt.h>
|
43 | #include <avr/io.h>
|
44 | #include <avr/pgmspace.h>
|
45 | #include <stdbool.h>
|
46 |
|
47 | #include "types.h"
|
48 |
|
49 |
|
50 | //! \brief Fuses for the .elf-file
|
51 | //!
|
52 | //! The following code lines define the fuses for the .elf-file. There is no more need to set them
|
53 | //! manually during the programming process.
|
54 | //! Fuses of the naked device: 0xFF, 0x00, 0xFF, 0xFE, 0xFF
|
55 |
|
56 | FUSES =
|
57 | {
|
58 | 0xFF, // JTAG User ID
|
59 | 0x0A, // WDPER set to 8s, no window
|
60 | 0xBE, // BOOTRST = BOOTLDR, BODPD = BOD enabled continuously during power down
|
61 | 0xFF, // Reserved byte with no function here.
|
62 | 0xFD, // ext. Reset enabled, no startup delay, WDT locked and enabled, JTAG I/F disabled
|
63 | 0xE3 // BODACT = BOD enabled continuously, EESAVE on, BODLEVEL = 2.6V
|
64 | };
|
65 |
|
66 |
|
67 | #if F_CPU != 32000000UL
|
68 | #error "ERROR: F_CPU must be 32MHz or baud rate generation won't work as designed!"
|
69 | #endif
|
70 |
|
71 | #ifndef USARTxx
|
72 | #error "ERROR: USARTxx must be defined with the correct port!"
|
73 | #endif
|
74 |
|
75 |
|
76 | //! \brief CCP write helper function written in assembly.
|
77 | //!
|
78 | //! This function is written in assembly because of the time critical operation of writing to
|
79 | //! the registers. (From clksys_driver.c of the Atmel application note AVR1003)
|
80 | //!
|
81 | //! \param address A pointer to the address to write to.
|
82 | //! \param value The value to put in to the register.
|
83 |
|
84 | void CCPWrite (tVUINT8* address, tUINT8 value)
|
85 | {
|
86 | tVUINT8* tmpAddr = address;
|
87 |
|
88 | #ifdef RAMPZ
|
89 | RAMPZ = 0;
|
90 | #endif
|
91 | asm volatile
|
92 | (
|
93 | "movw r30, %0" "\n\t"
|
94 | "ldi r16, %2" "\n\t"
|
95 | "out %3, r16" "\n\t"
|
96 | "st Z, %1" "\n\t"
|
97 | :
|
98 | : "r" (tmpAddr), "r" (value), "M" (CCP_IOREG_gc), "i" (&CCP)
|
99 | : "r16", "r30", "r31"
|
100 | );
|
101 | }
|
102 |
|
103 |
|
104 | //! \brief Check for an available character.
|
105 | //!
|
106 | //! Check for an available character in the receive buffer.
|
107 | //!
|
108 | //! \return True, if the flag is set.
|
109 |
|
110 | bool CharAvailable ()
|
111 | {
|
112 | return ((USARTxx.STATUS & USART_RXCIF_bm) != 0x00);
|
113 | }
|
114 |
|
115 |
|
116 | //! \brief getchar () replacement
|
117 | //!
|
118 | //! Simple, blocking getchar () replacement routine.
|
119 | //!
|
120 | //! \return Character, read from the serial interface of USART C1
|
121 |
|
122 | char GetChar ()
|
123 | {
|
124 | // Wait until something is ready to be read from the receive buffer.
|
125 | while ((USARTxx.STATUS & USART_RXCIF_bm) == 0x00)
|
126 | {
|
127 | // Reset watchdog timer while waiting for the next character.
|
128 | asm ("wdr");
|
129 | }
|
130 | return USARTxx.DATA;
|
131 | }
|
132 |
|
133 |
|
134 | //! \brief putchar () replacement
|
135 | //!
|
136 | //! Simple, blocking putchar () replacement.
|
137 | //!
|
138 | //! \param ch Character to be sent.
|
139 |
|
140 | void PutChar (char ch)
|
141 | {
|
142 | // Wait until the transmit buffer is free to accept the next character
|
143 | while ((USARTxx.STATUS & USART_DREIF_bm) == 0x00)
|
144 | {
|
145 | // Reset watchdog timer while waiting for the buffer to be free again.
|
146 | asm ("wdr");
|
147 | }
|
148 | USARTxx.DATA = ch;
|
149 |
|
150 | // Expand a <cr> to a <cr><lf> sequence.
|
151 | if (ch == '\r')
|
152 | PutChar ('\n');
|
153 | }
|
154 |
|
155 |
|
156 | //! \brief Main loop
|
157 |
|
158 | int main ()
|
159 | {
|
160 | // Turn off any interrupts, just in case.
|
161 | cli ();
|
162 |
|
163 | // ----------------------------------------------------------------------------------------------
|
164 |
|
165 | // Configure the oscillator from internal 2MHz clock to external 8MHz crystal and internal
|
166 | // PLL quadruplication.
|
167 |
|
168 | // Switch to external crystal (8 MHz) and wait for it to become stable.
|
169 | OSC.XOSCCTRL = OSC_FRQRANGE_2TO9_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
|
170 |
|
171 | OSC.CTRL = OSC_XOSCEN_bm | OSC_RC2MEN_bm;
|
172 | while ((OSC.STATUS & OSC_XOSCRDY_bm) != OSC_XOSCRDY_bm);
|
173 |
|
174 | // Set all the prescalers after the PLL to 1
|
175 | CCPWrite (&CLK.PSCTRL, CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc);
|
176 |
|
177 | // Activate the PLL with a multiplier of four to generate 32 MHz out of 8 MHz.
|
178 | OSC.PLLCTRL = 4 << OSC_PLLFAC_gp | OSC_PLLSRC_XOSC_gc;
|
179 |
|
180 | OSC.CTRL = OSC_XOSCEN_bm | OSC_RC2MEN_bm | OSC_PLLEN_bm;
|
181 | while ((OSC.STATUS & OSC_PLLRDY_bm) != OSC_PLLRDY_bm);
|
182 |
|
183 | // Switch from internal 2 MHz to 32 MHz PLL output.
|
184 | CCPWrite (&CLK.CTRL, CLK_SCLKSEL_PLL_gc);
|
185 |
|
186 | // ----------------------------------------------------------------------------------------------
|
187 |
|
188 | // Configure the USART C1 to 57600 baud 8N1, no handshake. Only polling will we used to
|
189 | // avoid any interrupts in the boot loader firmware.
|
190 |
|
191 | // Values calculated from baud rate and CPU Clock:
|
192 | // BSEL 1.079 (Select a BSEL Value from 0 to 4095)
|
193 | // BSCALE -5 (Select a BSCALE Value from -7 to 7)
|
194 | // CLK2X 0 (Select 2x speed mode)
|
195 | // Error% 0,01% (Error from selected baud rate)
|
196 | //
|
197 | // Values calculated from BSEL, BSCALE and CLK2X:
|
198 | // Baud rate 57.606 bits per second
|
199 | // Error% 0,01% error from selected baud rate
|
200 |
|
201 | #define BSEL 1079
|
202 | #define BSCALE 11 // -5 in 4-bit two's complement writing
|
203 |
|
204 | // Enable output functionality for the TXD pin.
|
205 | USARTport.DIRSET = USARTtxd;
|
206 |
|
207 | // Set baud rate generation to 57600 baud.
|
208 | USARTxx.BAUDCTRLA = (tUINT8) BSEL;
|
209 | USARTxx.BAUDCTRLB = (BSCALE << USART_BSCALE0_bp) | (BSEL >> 8);
|
210 | // Set USART to asynchronous mode and format to 8N1.
|
211 | USARTxx.CTRLC = USART_CHSIZE_8BIT_gc | USART_PMODE_DISABLED_gc | USART_CMODE_ASYNCHRONOUS_gc;
|
212 | // Enable Rx and Tx, no clock doubling, no multiprocessor communication at all.
|
213 | USARTxx.CTRLB = USART_RXEN_bm | USART_TXEN_bm;
|
214 | // Disable all interrupts.
|
215 | USARTxx.CTRLA = 0;
|
216 |
|
217 | #undef BSEL
|
218 | #undef BSCALE
|
219 |
|
220 | // ----------------------------------------------------------------------------------------------
|
221 |
|
222 | PutChar ('H');
|
223 | PutChar ('e');
|
224 | PutChar ('l');
|
225 | PutChar ('l');
|
226 | PutChar ('o');
|
227 | PutChar ('!');
|
228 | PutChar ('\r');
|
229 |
|
230 | while (1)
|
231 | {
|
232 | PutChar (GetChar ());
|
233 | }
|
234 | }
|