forked from mist-devel/mist-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhardware.c
336 lines (262 loc) · 9.63 KB
/
hardware.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
Copyright 2008, 2009 Jakub Bednarski
This file is part of Minimig
Minimig is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Minimig 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include "AT91SAM7S256.h"
#include "stdio.h"
#include "hardware.h"
#include "user_io.h"
#include "xmodem.h"
#include "ikbd.h"
uint8_t rstval = 0;
void __init_hardware(void)
{
*AT91C_WDTC_WDMR = AT91C_WDTC_WDDIS; // disable watchdog
*AT91C_RSTC_RMR = (0xA5 << 24) | AT91C_RSTC_URSTEN; // enable external user reset input
*AT91C_MC_FMR = FWS << 8; // Flash wait states
// configure clock generator
*AT91C_CKGR_MOR = AT91C_CKGR_MOSCEN | (40 << 8);
while (!(*AT91C_PMC_SR & AT91C_PMC_MOSCS));
*AT91C_CKGR_PLLR = AT91C_CKGR_OUT_0 | AT91C_CKGR_USBDIV_1 | (25 << 16) | (40 << 8) | 5; // DIV=5 MUL=26 USBDIV=1 (2) PLLCOUNT=40
while (!(*AT91C_PMC_SR & AT91C_PMC_LOCK));
*AT91C_PMC_MCKR = AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
*AT91C_PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
*AT91C_PIOA_PER = 0xFFFFFFFF; // enable pio on all pins
*AT91C_PIOA_SODR = DISKLED; // led off
#ifdef USB_PUP
// disable usb d+/d- pullups if present
*AT91C_PIOA_OER = USB_PUP;
*AT91C_PIOA_PPUDR = USB_PUP;
*AT91C_PIOA_SODR = USB_PUP;
#endif
// enable joystick ports
#ifdef JOY0
*AT91C_PIOA_PPUER = JOY0;
#endif
#ifdef JOY1
*AT91C_PIOA_PPUER = JOY1;
#endif
#ifdef SD_WP
// enable SD card signals
*AT91C_PIOA_PPUER = SD_WP | SD_CD;
#endif
*AT91C_PIOA_SODR = MMC_SEL | FPGA0 | FPGA1 | FPGA2; // set output data register
// output enable register
*AT91C_PIOA_OER = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
// pull-up disable register
*AT91C_PIOA_PPUDR = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
#ifdef XILINX_CCLK
// xilinx interface
*AT91C_PIOA_SODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
*AT91C_PIOA_OER = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
*AT91C_PIOA_PPUDR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B |
XILINX_INIT_B | XILINX_DONE;
#endif
#ifdef ALTERA_DCLK
// altera interface
*AT91C_PIOA_SODR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
*AT91C_PIOA_OER = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
*AT91C_PIOA_PPUDR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG |
ALTERA_NSTATUS | ALTERA_DONE;
#endif
#ifdef MMC_CLKEN
// MMC_CLKEN may be present
// (but is not used anymore, so it's only setup passive)
*AT91C_PIOA_SODR = MMC_CLKEN;
*AT91C_PIOA_PPUDR = MMC_CLKEN;
#endif
#ifdef USB_SEL
*AT91C_PIOA_SODR = USB_SEL;
*AT91C_PIOA_OER = USB_SEL;
*AT91C_PIOA_PPUDR = USB_SEL;
#endif
// Enable peripheral clock in the PMC
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
}
void hexdump(void *data, uint16_t size, uint16_t offset) {
uint8_t i, b2c;
uint16_t n=0;
char *ptr = data;
if(!size) return;
while(size>0) {
iprintf("%04x: ", n + offset);
b2c = (size>16)?16:size;
for(i=0;i<b2c;i++) iprintf("%02x ", 0xff&ptr[i]);
iprintf(" ");
for(i=0;i<(16-b2c);i++) iprintf(" ");
for(i=0;i<b2c;i++) iprintf("%c", isprint(ptr[i])?ptr[i]:'.');
iprintf("\n");
ptr += b2c;
size -= b2c;
n += b2c;
}
}
// A buffer of 256 bytes makes index handling pretty trivial
volatile static unsigned char tx_buf[256];
volatile static unsigned char tx_rptr, tx_wptr;
volatile static unsigned char rx_buf[256];
volatile static unsigned char rx_rptr, rx_wptr;
void Usart0IrqHandler(void) {
// Read USART status
unsigned char status = AT91C_BASE_US0->US_CSR;
// received something?
if(status & AT91C_US_RXRDY) {
// read byte from usart
unsigned char c = AT91C_BASE_US0->US_RHR;
// only store byte if rx buffer is not full
if((unsigned char)(rx_wptr + 1) != rx_rptr) {
// there's space in buffer: use it
rx_buf[rx_wptr++] = c;
}
}
// ready to transmit further bytes?
if(status & AT91C_US_TXRDY) {
// further bytes to send in buffer?
if(tx_wptr != tx_rptr)
// yes, simply send it and leave irq enabled
AT91C_BASE_US0->US_THR = tx_buf[tx_rptr++];
else
// nothing else to send, disable interrupt
AT91C_BASE_US0->US_IDR = AT91C_US_TXRDY;
}
}
// check usart rx buffer for data
void USART_Poll(void) {
if(user_io_dip_switch1())
xmodem_poll();
while(rx_wptr != rx_rptr) {
// this can a little be optimized by sending whole buffer parts
// at once and not just single bytes. But that's probably not
// worth the effort.
char chr = rx_buf[rx_rptr++];
if(user_io_dip_switch1()) {
// if in debug mode use xmodem for file reception
xmodem_rx_byte(chr);
} else {
iprintf("USART RX %d (%c)\n", chr, chr);
// data available -> send via user_io to core
user_io_serial_tx(&chr, 1);
}
}
}
void USART_Write(unsigned char c) {
#if 0
while(!(AT91C_BASE_US0->US_CSR & AT91C_US_TXRDY));
AT91C_BASE_US0->US_THR = c;
#else
if((AT91C_BASE_US0->US_CSR & AT91C_US_TXRDY) && (tx_wptr == tx_rptr)) {
// transmitter ready and buffer empty? -> send directly
AT91C_BASE_US0->US_THR = c;
} else {
// transmitter is not ready: block until space in buffer
while((unsigned char)(tx_wptr + 1) == tx_rptr);
// there's space in buffer: use it
tx_buf[tx_wptr++] = c;
}
AT91C_BASE_US0->US_IER = AT91C_US_TXRDY; // enable interrupt
#endif
}
void USART_Init(unsigned long baudrate) {
// Configure PA5 and PA6 for USART0 use
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0;
// Enable the peripheral clock in the PMC
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_US0;
// Reset and disable receiver & transmitter
AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS | AT91C_US_TXDIS;
// Configure USART0 mode
AT91C_BASE_US0->US_MR = AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS |
AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT | AT91C_US_CHMODE_NORMAL;
// Configure USART0 rate
AT91C_BASE_US0->US_BRGR = MCLK / 16 / baudrate;
// Enable receiver & transmitter
AT91C_BASE_US0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
// tx buffer is initially empty
tx_rptr = tx_wptr = 0;
// and so is rx buffer
rx_rptr = rx_wptr = 0;
// Set the USART0 IRQ handler address in AIC Source
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_US0] = (unsigned int)Usart0IrqHandler;
AT91C_BASE_AIC->AIC_IECR = (1<<AT91C_ID_US0);
AT91C_BASE_US0->US_IER = AT91C_US_RXRDY; // enable rx interrupt
}
unsigned long CheckButton(void)
{
#ifdef BUTTON
return((~*AT91C_PIOA_PDSR) & BUTTON);
#else
return user_io_menu_button();
#endif
}
void timer0_c_irq_handler(void) {
//* Acknowledge interrupt status
unsigned int dummy = AT91C_BASE_TC0->TC_SR;
ikbd_update_time();
}
void Timer_Init(void) {
unsigned int dummy;
//* Open timer0
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;
//* Disable the clock and the interrupts
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS ;
AT91C_BASE_TC0->TC_IDR = 0xFFFFFFFF ;
//* Clear status bit
dummy = AT91C_BASE_TC0->TC_SR;
//* Set the Mode of the Timer Counter
AT91C_BASE_TC0->TC_CMR = 0x04; // :1024
//* Enable the clock
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN ;
//* Open Timer 0 interrupt
//* Disable the interrupt on the interrupt controller
AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_TC0;
//* Save the interrupt handler routine pointer and the interrupt priority
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int)timer0_c_irq_handler;
//* Store the Source Mode Register
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = 1 | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
//* Clear the interrupt on the interrupt controller
AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_TC0;
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS; // IRQ enable CPC
AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_TC0;
//* Start timer0
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG ;
*AT91C_PITC_PIMR = AT91C_PITC_PITEN | ((MCLK / 16 / 1000 - 1) & AT91C_PITC_PIV); // counting period 1ms
}
// 12 bits accuracy at 1ms = 4096 ms
unsigned long GetTimer(unsigned long offset)
{
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
systimer += offset << 20;
return (systimer); // valid bits [31:20]
}
unsigned long CheckTimer(unsigned long time)
{
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
time -= systimer;
return(time > (1UL << 31));
}
void WaitTimer(unsigned long time)
{
time = GetTimer(time);
while (!CheckTimer(time));
}
void TIMER_wait(unsigned long ms) {
WaitTimer(ms);
}
char mmc_inserted() {
return !(*AT91C_PIOA_PDSR & SD_CD);
}
char mmc_write_protected() {
return (*AT91C_PIOA_PDSR & SD_WP);
}