2 * Copyright © 2014 Keith Packard <keithp@keithp.com>
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; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #define AO_TRNG_SPI_BUS 1
22 static uint32_t spi_speed = AO_SPI_SPEED_4MHz;
24 #define AO_TRNG_SPI_BUF 1024
28 static uint8_t *spi_buf;
29 static uint8_t *spi_head, *spi_tail;
30 static uint8_t spi_wakeup;
39 spi_buf = ao_usb_alloc(AO_TRNG_SPI_BUF);
41 ao_spi_get(AO_TRNG_SPI_BUS, spi_speed);
44 ao_spi_recv_ring_start(spi_buf, AO_TRNG_SPI_BUF, &spi_head, &spi_tail, &spi_wakeup, AO_TRNG_SPI_BUS);
45 while (!ao_usb_out_avail) {
46 ao_arch_block_interrupts();
47 while (spi_head == spi_tail) {
49 ao_sleep(&spi_wakeup);
51 ao_arch_release_interrupts();
52 if (spi_tail > spi_head)
53 end = spi_buf + AO_TRNG_SPI_BUF;
56 this_time = end - spi_tail;
59 ao_usb_write(spi_tail, this_time);
60 spi_tail += this_time;
61 if (spi_tail == spi_buf + AO_TRNG_SPI_BUF)
64 ao_spi_put(AO_TRNG_SPI_BUS);
72 static uint8_t random[32];
75 ao_spi_get(AO_TRNG_SPI_BUS, spi_speed);
76 ao_spi_recv(random, sizeof (random), AO_TRNG_SPI_BUS);
77 ao_spi_put(AO_TRNG_SPI_BUS);
78 for (i = 0; i < sizeof (random); i++)
79 printf (" %02x", random[i]);
84 #define ADC_RING_SIZE 512
86 static uint8_t *adc_ring;
87 static uint16_t adc_head, adc_tail;
88 static uint16_t adc_wake;
90 void lpc_adc_isr(void)
96 next = (this + 1) & (ADC_RING_SIZE - 1);
97 if (next == adc_tail) {
101 adc_ring[this] = lpc_adc.dr[6] >> 8;
104 /* If there are enough entries, wake up any waiters
106 avail = (next - adc_tail) & (ADC_RING_SIZE - 1);
107 if (avail >= adc_wake) {
109 ao_wakeup(&adc_wake);
113 #define AO_ADC_CLKDIV (AO_LPC_SYSCLK / 450000)
116 ao_trng_adc_init(void)
118 adc_ring = ao_usb_alloc(ADC_RING_SIZE);
120 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
121 lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
123 /* Enable interrupt when AO_ADC_6 is complete */
126 lpc_nvic_set_enable(LPC_ISR_ADC_POS);
127 lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
130 ao_enable_analog(0, 11, 0);
133 ao_enable_analog(0, 12, 1);
136 ao_enable_analog(0, 13, 2);
139 ao_enable_analog(0, 14, 3);
142 ao_enable_analog(0, 15, 4);
145 ao_enable_analog(0, 16, 5);
148 ao_enable_analog(0, 22, 6);
151 ao_enable_analog(0, 23, 7);
154 lpc_adc.cr = ((1 << (LPC_ADC_CR_SEL + 6)) |
155 (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
156 (1 << LPC_ADC_CR_BURST) |
157 (LPC_ADC_CR_CLKS_9 << LPC_ADC_CR_CLKS));
161 ao_trng_adc_dump(void)
165 while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 16) {
166 lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
170 printf("adc_head %d tail %d\n", adc_head, adc_tail);
172 for (i = 0; i < 16; i++) {
173 printf(" %4d", adc_ring[adc_tail]);
174 adc_tail = (adc_tail + 1) & (ADC_RING_SIZE - 1);
186 while (!ao_usb_out_avail) {
187 ao_arch_block_interrupts();
188 while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 64) {
189 lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
193 ao_arch_release_interrupts();
195 this_time = ADC_RING_SIZE - adc_tail;
198 ao_usb_write(&adc_ring[adc_tail], this_time);
199 adc_tail = (adc_tail + this_time) & (ADC_RING_SIZE - 1);
209 if (ao_cmd_lex_u32 == 0 || ao_cmd_status != ao_cmd_success) {
210 ao_cmd_status = ao_cmd_success;
211 printf ("Current spi speed %d\n", spi_speed);
213 spi_speed = ao_cmd_lex_u32;
217 static const struct ao_cmds ao_trng_cmds[] = {
218 // { ao_trng_test, "R\0Dump some random numbers" },
219 { ao_trng_run, "s\0Send random bits until char" },
220 { ao_trng_speed, "S <speed>\0Set SPI speed (48MHz/speed)" },
221 { ao_trng_adc_dump, "a\0Dump ADC data" },
239 ao_led_init(LEDS_AVAILABLE);
243 ao_cmd_register(ao_trng_cmds);
245 ao_start_scheduler();