-
Notifications
You must be signed in to change notification settings - Fork 10
/
hardware.c
221 lines (167 loc) · 6.02 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
/**
* LPC1114 Synthesizer
* Matt Sarnoff (msarnoff.org)
* November 24, 2013
*
* Hardware-related subroutines.
*/
#include "hardware.h"
/**
* Starts the ADC for all channels.
*/
void adc_init(void)
{
/* Disable Power down bit to the ADC block. */
SCB_PDRUNCFG &= ~(SCB_PDRUNCFG_ADC);
/* Enable AHB clock to the ADC. */
SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_ADC);
/* Set AD0 to analog input */
IOCON_JTAG_TDI_PIO0_11 = IOCON_JTAG_TDI_PIO0_11_FUNC_AD0|IOCON_JTAG_TDI_PIO0_11_MODE_PULLUP;
/* Set AD1 to analog input */
IOCON_JTAG_TMS_PIO1_0 = IOCON_JTAG_TMS_PIO1_0_FUNC_AD1;
/* Set AD2 to analog input */
IOCON_JTAG_TDO_PIO1_1 = IOCON_JTAG_TDO_PIO1_1_FUNC_AD2;
/* Set AD3 to analog input */
IOCON_JTAG_nTRST_PIO1_2 = IOCON_JTAG_nTRST_PIO1_2_FUNC_AD3;
/* Set AD4 to analog input */
IOCON_SWDIO_PIO1_3 = IOCON_SWDIO_PIO1_3_FUNC_AD4;
/* Set AD5 to analog input */
IOCON_PIO1_4 = IOCON_PIO1_4_FUNC_AD5;
/* Set channel and clock divider but don't start */
ADC_AD0CR = (ADC_AD0CR_SEL_AD0 | /* SEL=1,select channel 0 on ADC0 */
(11 << 8) | /* CLKDIV = 48MHz/11 = 4.36MHz */
ADC_AD0CR_BURST_SWMODE | /* BURST = 0, no BURST, software controlled */
ADC_AD0CR_CLKS_10BITS | /* CLKS = 0, 11 clocks/10 bits */
ADC_AD0CR_START_NOSTART | /* START = 0 A/D conversion stops */
ADC_AD0CR_EDGE_RISING); /* EDGE = 0 (CAP/MAT signal falling, trigger A/D conversion) */
}
/**
* Read a 10-bit value from the specified ADC channel.
* Blocks until conversion has finished.
*/
uint32_t adc_read_channel(uint8_t channel)
{
/* Deselect all channels */
ADC_AD0CR &= ~ADC_AD0CR_SEL_MASK;
/* Start converting now on the appropriate channel */
ADC_AD0CR |= ADC_AD0CR_START_STARTNOW | (1 << channel);
uint32_t regVal = 0;
do {
regVal = *(pREG32(ADC_AD0DR0+(channel*4)));
} while ((regVal & ADC_DR_DONE) == 0);
/* stop ADC */
ADC_AD0CR &= ~ADC_AD0CR_START_MASK;
/* return 0 if an overrun occurred */
if (regVal & ADC_DR_OVERRUN) {
return 0;
}
/* return conversion results */
return (regVal >> 6) & 0x3FF;
}
/**
* Set up SPI master operation (output only) in mode 0.
*/
void spi_init(void)
{
/* Reset SSP */
SCB_PRESETCTRL &= ~SCB_PRESETCTRL_SSP0_MASK;
SCB_PRESETCTRL |= SCB_PRESETCTRL_SSP0_RESETDISABLED;
/* Enable AHB clock to the SSP domain. */
SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_SSP0);
/* Set P0.8 to SSP MISO */
IOCON_PIO0_8 = IOCON_PIO0_8_FUNC_MISO0;
/* Set P0.9 to SSP MOSI */
IOCON_PIO0_9 = IOCON_PIO0_9_FUNC_MOSI0;
/* Set P0.16 to SSP SCK */
IOCON_SCKLOC = IOCON_SCKLOC_SCKPIN_PIO0_6;
IOCON_PIO0_6 = IOCON_PIO0_6_FUNC_SCK;
IOCON_JTAG_TCK_PIO0_10 = IOCON_JTAG_TCK_PIO0_10_FUNC_GPIO;
GPIO_GPIO0DIR |= (1 << 10);
gpio0_set_pin_low(10);
/* Set P0.2 to SSP SSEL */
IOCON_PIO0_2 = IOCON_PIO0_2_FUNC_SSEL;
/* 16-bit transfers, mode 0, 1 bit per prescaler clock cycle */
SSP_SSP0CR0 = SSP_SSP0CR0_DSS_16BIT |
SSP_SSP0CR0_FRF_SPI |
SSP_SSP0CR0_CPOL_HIGH |
SSP_SSP0CR0_CPHA_SECOND;
/* 1/4 clock prescaler */
SSP_SSP0CPSR = SSP_SSP0CPSR_CPSDVSR_DIV4;
/* SPI master enabled */
SSP_SSP0CR1 = SSP_SSP0CR1_LBM_NORMAL |
SSP_SSP0CR1_SSE_ENABLED |
SSP_SSP0CR1_MS_MASTER;
}
void uart_init(uint16_t divisor)
{
/* Set 1.6 UART RXD */
IOCON_PIO1_6 &= ~IOCON_PIO1_6_FUNC_MASK;
IOCON_PIO1_6 |= IOCON_PIO1_6_FUNC_UART_RXD;
/* Set 1.7 UART TXD */
IOCON_PIO1_7 &= ~IOCON_PIO1_7_FUNC_MASK;
IOCON_PIO1_7 |= IOCON_PIO1_7_FUNC_UART_TXD;
/* Enable UART clock */
SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_UART);
SCB_UARTCLKDIV = SCB_UARTCLKDIV_DIV1; /* divided by 1 */
/* 8 bits, no parity, 1 stop bit, prepare to set baud rate */
UART_U0LCR = UART_U0LCR_Word_Length_Select_8Chars |
UART_U0LCR_Stop_Bit_Select_1Bits |
UART_U0LCR_Parity_Disabled |
UART_U0LCR_Divisor_Latch_Access_Enabled;
/* Set baud rate */
UART_U0DLM = divisor >> 8;
UART_U0DLL = divisor & 0xFF;
UART_U0LCR &= (~UART_U0LCR_Divisor_Latch_Access_MASK);
/* Enable RX and TX FIFO */
UART_U0FCR = UART_U0FCR_FIFO_Enabled |
UART_U0FCR_Tx_FIFO_Reset |
UART_U0FCR_Rx_FIFO_Reset;
/* Enable the UART interrupt */
NVIC_EnableIRQ(UART_IRQn);
UART_U0IER = UART_U0IER_RBR_Interrupt_Enabled;
}
void uart_send_byte(uint8_t byte)
{
while (!(UART_U0LSR & UART_U0LSR_THRE)) {}
UART_U0THR = byte;
}
void timer32_init(int timernum, uint32_t rate)
{
if (timernum == 0) {
/* Enable the clock for CT32B0 */
SCB_SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_CT32B0;
/* Set rate */
TMR_TMR32B0MR0 = rate;
/* Configure match control register to raise an interrupt and reset on MR0 */
TMR_TMR32B0MCR = (TMR_TMR32B0MCR_MR0_INT_ENABLED | TMR_TMR32B0MCR_MR0_RESET_ENABLED);
/* Enable the TIMER0 interrupt */
NVIC_EnableIRQ(TIMER_32_0_IRQn);
/* Start the timer */
TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_ENABLED;
} else {
SCB_SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_CT32B1;
TMR_TMR32B1MR0 = rate;
TMR_TMR32B1MCR = (TMR_TMR32B1MCR_MR0_INT_ENABLED | TMR_TMR32B1MCR_MR0_RESET_ENABLED);
NVIC_EnableIRQ(TIMER_32_1_IRQn);
TMR_TMR32B1TCR = TMR_TMR32B1TCR_COUNTERENABLE_ENABLED;
}
}
void pwm_init(uint16_t pulsewidth)
{
/* Enable clock for 16-bit timer 1 */
SCB_SYSAHBCLKCTRL |= SCB_SYSAHBCLKCTRL_CT16B1;
/* Configure PIO1.9 (pin 18) as 16-bit timer 1 MAT0 output */
IOCON_PIO1_9 = IOCON_PIO1_9_FUNC_CT16B1_MAT0;
/* Frequency; PWM period resets at this value */
TMR_TMR16B1MR3 = pulsewidth;
/* Initial duty cycle */
TMR_TMR16B1MR0 = 0;
/* Reset timer when value reaches MR3 */
TMR_TMR16B1MCR = TMR_TMR16B1MCR_MR3_RESET_ENABLED;
/* Toggle pin when value reaches MR0 */
TMR_TMR16B1EMR = TMR_TMR16B1EMR_EM0|TMR_TMR16B1EMR_EMC0_TOGGLE;
/* Enable PWM0 and PWM3 */
TMR_TMR16B1PWMC = TMR_TMR16B1PWMC_PWM0_ENABLED|TMR_TMR16B1PWMC_PWM3_ENABLED;
/* Start the timer */
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERENABLE_ENABLED;
}