xref: /btstack/port/samv71-xplained-atwilc3000/main.c (revision d13e5cf6603f8d92493ebd8a19ad22c4dfb7a126)
1 #define BTSTACK_FILE__ "main.c"
2 
3 #include "asf.h"
4 #include "stdio_serial.h"
5 #include "conf_board.h"
6 #include "conf_clock.h"
7 
8 // BTstack
9 #include "btstack_chipset_atwilc3000.h"
10 #include "btstack_debug.h"
11 #include "btstack_memory.h"
12 #include "btstack_run_loop.h"
13 #include "btstack_run_loop_embedded.h"
14 #include "hal_uart_dma.h"
15 #include "hal_cpu.h"
16 #include "hal_tick.h"
17 #include "hci.h"
18 #include "hci_dump.h"
19 #include "hci_dump_embedded_stdout.h"
20 #include "hci_transport.h"
21 #include "hci_transport_h4.h"
22 #include "wilc3000_ble_firmware.h"
23 
24 // #define USE_XDMAC_FOR_USART
25 #define XDMA_CH_UART_TX  0
26 #define XDMA_CH_UART_RX  1
27 
28 /** All interrupt mask. */
29 #define ALL_INTERRUPT_MASK   0xffffffff
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 extern int btstack_main(int argc, const char * argv[]);
36 
37 static void dummy_handler(void){}
38 static void (*tick_handler)(void) = &dummy_handler;
39 
40 static btstack_uart_config_t uart_config;
41 
42 static hci_transport_config_uart_t transport_config = {
43 	HCI_TRANSPORT_CONFIG_UART,
44 	2000000,  // directly use high baud rate after config
45 	0, 		  // use 0 to skip baud rate change from 115200 to X for debugging purposes
46 	1,        // flow control
47 	NULL,
48 };
49 
50 /**
51  *  \brief Handler for System Tick interrupt.
52  */
53 void SysTick_Handler(void)
54 {
55 	tick_handler();
56 }
57 
58 // Debug console Output
59 
60 /**
61  *  Configure UART console.
62  */
63 // [main_console_configure]
64 static void configure_console(void)
65 {
66 	const usart_serial_options_t uart_serial_options = {
67 		.baudrate = CONF_UART_BAUDRATE,
68 #ifdef CONF_UART_CHAR_LENGTH
69 		.charlength = CONF_UART_CHAR_LENGTH,
70 #endif
71 		.paritytype = CONF_UART_PARITY,
72 #ifdef CONF_UART_STOP_BITS
73 		.stopbits = CONF_UART_STOP_BITS,
74 #endif
75 	};
76 
77 	/* Configure console UART. */
78 	sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
79 	stdio_serial_init(CONF_UART, &uart_serial_options);
80 }
81 
82 // Debug console Input
83 
84 #include "btstack_stdin.h"
85 
86 static void (*stdin_handler)(char c);
87 static btstack_data_source_t stdin_data_source;
88 
89 static void btstack_stdin_process(struct btstack_data_source *ds, btstack_data_source_callback_type_t callback_type){
90 	// try to read from console
91 	uint32_t stdin_character;
92 	uint32_t res = usart_read(CONF_UART, &stdin_character);
93 	if (res) return;
94 
95 	if (stdin_handler){
96 		(*stdin_handler)(stdin_character & 0xff);
97 	}
98 }
99 
100 void btstack_stdin_setup(void (*handler)(char c)){
101 	// set handler
102 	stdin_handler = handler;
103 
104 	// set up polling data_source
105 	btstack_run_loop_set_data_source_handler(&stdin_data_source, &btstack_stdin_process);
106 	btstack_run_loop_enable_data_source_callbacks(&stdin_data_source, DATA_SOURCE_CALLBACK_POLL);
107 	btstack_run_loop_add_data_source(&stdin_data_source);
108 }
109 
110 // [main_console_configure]
111 
112 /**
113  * \brief Wait for the given number of milliseconds (ticks
114  * generated by the SAM's microcontrollers's system tick).
115  *
116  * \param ul_dly_ticks  Delay to wait for, in milliseconds.
117  */
118 // [main_ms_delay]
119 static void mdelay(uint32_t delay_in_ms)
120 {
121 	// delay_ms(delay_in_ms);
122 	uint32_t time_to_wait = btstack_run_loop_get_time_ms() + delay_in_ms;
123 	while (btstack_run_loop_get_time_ms() < time_to_wait);
124 }
125 // [main_ms_delay]
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 // hal_cpu.h implementation
129 ////////////////////////////////////////////////////////////////////////////////
130 // hal_led.h implementation
131 #include "hal_led.h"
132 void hal_led_off(void);
133 void hal_led_on(void);
134 
135 void hal_led_off(void){
136 	// gpio_set_pin_low(GPIOA, GPIO_LED2);
137 }
138 void hal_led_on(void){
139 	// gpio_set_pin_high(GPIOA, GPIO_LED2);
140 }
141 void hal_led_toggle(void){
142 	// gpio_toggle_pin(GPIOA, GPIO_LED2);
143 }
144 
145 // hal_cpu.h implementation
146 #include "hal_cpu.h"
147 
148 void hal_cpu_disable_irqs(void){
149 	//__disable_irq();
150 }
151 
152 void hal_cpu_enable_irqs(void){
153 	// __enable_irq();
154 }
155 
156 void hal_cpu_enable_irqs_and_sleep(void){
157 	hal_led_off();
158 	// __enable_irq();
159 	// __asm__("wfe");	// go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag
160 
161 	// note: hal_uart_needed_during_sleep can be used to disable peripheral clock if it's not needed for a timer
162 	hal_led_on();
163 }
164 
165 
166 #ifndef USE_XDMAC_FOR_USART
167 // RX state
168 static volatile uint16_t  bytes_to_read = 0;
169 static volatile uint8_t * rx_buffer_ptr = 0;
170 
171 // TX state
172 static volatile uint16_t  bytes_to_write = 0;
173 static volatile uint8_t * tx_buffer_ptr = 0;
174 #endif
175 
176 static volatile int       rx_notify;
177 static volatile int       tx_notify;
178 
179 static int simulate_flowcontrol;
180 
181 // handlers
182 static void (*rx_done_handler)(void) = dummy_handler;
183 static void (*tx_done_handler)(void) = dummy_handler;
184 static void (*cts_irq_handler)(void) = dummy_handler;
185 
186 // @note While the Atmel SAM S7x data sheet states
187 // "The hardware handshaking feature enables an out-of-band flow control by automatic management
188 //  of the pins RTS and CTS.",
189 // I didn't see RTS going up automatically up, ever. So, at least for RTS, the automatic management
190 // is just a glorified GPIO pin control feature, which provides no benefit, but irritates a lot
191 
192 // J505:6
193 #define DEBUG_PIN_1 PIO_PD16_IDX
194 // J505:5
195 #define DEBUG_PIN_2 PIO_PD15_IDX
196 
197 static inline void hal_uart_rts_high(void){
198 	if (!simulate_flowcontrol) return;
199 	ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_HIGH);
200 	BOARD_USART->US_CR = US_CR_RTSEN;
201 }
202 static inline void hal_uart_rts_low(void){
203 	if (!simulate_flowcontrol) return;
204 	ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW);
205 	BOARD_USART->US_CR = US_CR_RTSDIS;
206 }
207 
208 /**
209  */
210 static int hal_uart_dma_initialized = 0;
211 void hal_uart_dma_init(void)
212 {
213 	if (hal_uart_dma_initialized){
214 		log_info("hal_uart_dma_init already initialized");
215 		return;
216 	}
217 	hal_uart_dma_initialized = 1;
218 
219 	// debug
220 #ifdef DEBUG_PIN_1
221 	ioport_set_pin_dir(DEBUG_PIN_1, IOPORT_DIR_OUTPUT);
222 	ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_LOW);
223 #endif
224 #ifdef DEBUG_PIN_2
225 	ioport_set_pin_dir(DEBUG_PIN_2, IOPORT_DIR_OUTPUT);
226 	ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW);
227 #endif
228 	// power on
229 	ioport_set_pin_dir(BLUETOOTH_CHP_EN, IOPORT_DIR_OUTPUT);
230 	ioport_set_pin_level(BLUETOOTH_CHP_EN, IOPORT_PIN_LEVEL_HIGH);
231 
232 	// reset
233 	ioport_set_pin_dir(BLUETOOTH_RESET, IOPORT_DIR_OUTPUT);
234 	ioport_set_pin_level(BLUETOOTH_RESET, IOPORT_PIN_LEVEL_LOW);
235 	mdelay(250);
236 	ioport_set_pin_level(BLUETOOTH_RESET, IOPORT_PIN_LEVEL_HIGH);
237 	mdelay(250);
238 
239 	/* Enable the peripheral clock in the PMC. */
240 	sysclk_enable_peripheral_clock(BOARD_ID_USART);
241 
242 	// configure Bluetooth USART
243 	const sam_usart_opt_t bluetooth_settings = {
244 		115200,
245 		US_MR_CHRL_8_BIT,
246 		US_MR_PAR_NO,
247 		US_MR_NBSTOP_1_BIT,
248 		US_MR_CHMODE_NORMAL,
249 		/* This field is only used in IrDA mode. */
250 		0
251 	};
252 
253 	/* Configure USART mode. */
254 	simulate_flowcontrol = 0;
255 	usart_init_rs232(BOARD_USART, &bluetooth_settings, sysclk_get_peripheral_hz());
256 	// Set RTS = 0 (normal mode)
257 	BOARD_USART->US_CR = US_CR_RTSEN;
258 
259 	/* Disable all the interrupts. */
260 	usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK);
261 
262 	/* Enable TX & RX function. */
263 	usart_enable_tx(BOARD_USART);
264 	usart_enable_rx(BOARD_USART);
265 
266 	/* Configure and enable interrupt of USART. */
267 	NVIC_EnableIRQ(USART_IRQn);
268 
269 #ifdef USE_XDMAC_FOR_USART
270 
271 	// setup XDMAC
272 
273 	/* Initialize and enable DMA controller */
274 	pmc_enable_periph_clk(ID_XDMAC);
275 
276 	/* Enable XDMA interrupt */
277 	NVIC_ClearPendingIRQ(XDMAC_IRQn);
278 	NVIC_SetPriority( XDMAC_IRQn ,1);
279 	NVIC_EnableIRQ(XDMAC_IRQn);
280 
281 	// Setup XDMA Channel for USART TX
282 	xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)&BOARD_USART->US_THR);
283 	xdmac_channel_set_config(XDMAC, XDMA_CH_UART_TX,
284 		XDMAC_CC_TYPE_PER_TRAN |
285 		XDMAC_CC_DSYNC_MEM2PER |
286 		XDMAC_CC_MEMSET_NORMAL_MODE |
287 		XDMAC_CC_MBSIZE_SINGLE |
288 		XDMAC_CC_DWIDTH_BYTE |
289 		XDMAC_CC_SIF_AHB_IF0 |
290 		XDMAC_CC_DIF_AHB_IF1 |
291 		XDMAC_CC_SAM_INCREMENTED_AM |
292 		XDMAC_CC_DAM_FIXED_AM |
293 		XDMAC_CC_CSIZE_CHK_1 |
294 		XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_TX)
295 	);
296 	xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_TX, 0);
297 	xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
298 	xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
299 	xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_TX, 0);
300 	xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_TX, 0);
301 	xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_TX);
302 	xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_TX, XDMAC_CIE_BIE);
303 
304 	// Setup XDMA Channel for USART RX
305 	xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)&BOARD_USART->US_RHR);
306 	xdmac_channel_set_config(XDMAC, XDMA_CH_UART_RX,
307 		XDMAC_CC_TYPE_PER_TRAN |
308 		XDMAC_CC_DSYNC_PER2MEM |
309 		XDMAC_CC_MEMSET_NORMAL_MODE |
310 		XDMAC_CC_MBSIZE_SINGLE |
311 		XDMAC_CC_DWIDTH_BYTE |
312 		XDMAC_CC_SIF_AHB_IF1 |
313 		XDMAC_CC_DIF_AHB_IF0 |
314 		XDMAC_CC_SAM_FIXED_AM |
315 		XDMAC_CC_DAM_INCREMENTED_AM |
316 		XDMAC_CC_CSIZE_CHK_1 |
317 		XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_RX)
318 	);
319 	xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_RX, 0);
320 	xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
321 	xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
322 	xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_RX, 0);
323 	xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_RX, 0);
324 	xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_RX);
325 	xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_RX, XDMAC_CIE_BIE);
326 #endif
327 }
328 
329 void hal_uart_dma_set_sleep(uint8_t sleep){
330 }
331 
332 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
333 	rx_done_handler = the_block_handler;
334 }
335 
336 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
337 	tx_done_handler = the_block_handler;
338 }
339 
340 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){
341 	cts_irq_handler = the_irq_handler;
342 }
343 
344 int  hal_uart_dma_set_baud(uint32_t baud){
345 	/* Disable TX & RX function. */
346 	usart_disable_tx(BOARD_USART);
347 	usart_disable_rx(BOARD_USART);
348 	uint32_t res = usart_set_async_baudrate(BOARD_USART, baud, sysclk_get_peripheral_hz());
349 	if (res){
350 		log_error("hal_uart_dma_set_baud library call failed");
351 	}
352 
353 	/* Enable TX & RX function. */
354 	usart_enable_tx(BOARD_USART);
355 	usart_enable_rx(BOARD_USART);
356 
357 	log_info("set baud rate %u", (int) baud);
358 	return 0;
359 }
360 
361 int  hal_uart_dma_set_flowcontrol(int flowcontrol){
362 	log_info("hal_uart_dma_set_flowcontrol %u", flowcontrol);
363 	simulate_flowcontrol = flowcontrol;
364 	if (flowcontrol){
365 		/* Set hardware handshaking mode. */
366 		BOARD_USART->US_MR = (BOARD_USART->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_HW_HANDSHAKING;
367 		hal_uart_rts_high();
368 	} else {
369 		/* Set nomal mode. */
370 		BOARD_USART->US_MR = (BOARD_USART->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_NORMAL;
371 		// Set RTS = 0 (normal mode)
372 		BOARD_USART->US_CR = US_CR_RTSEN;
373 	}
374 	return 0;
375 }
376 
377 void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
378 
379 	tx_notify = 1;
380 
381 #ifdef USE_XDMAC_FOR_USART
382 	xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_TX);
383 	xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)data);
384 	xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_TX, size);
385 	xdmac_channel_enable(XDMAC, XDMA_CH_UART_TX);
386 #else
387 	if (bytes_to_write){
388 		log_error("send block, bytes to write %u", bytes_to_write);
389 		return;
390 	}
391     tx_buffer_ptr = (uint8_t *) data;
392     bytes_to_write = size;
393 	usart_enable_interrupt(BOARD_USART, US_IER_TXRDY);
394 #endif
395 }
396 
397 void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
398 
399 #ifdef DEBUG_PIN_1
400 	ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_HIGH);
401 #endif
402 
403 	hal_uart_rts_low();
404 
405 	rx_notify = 1;
406 
407 #ifdef USE_XDMAC_FOR_USART
408 	xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_RX);
409 	xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)data);
410 	xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_RX, size);
411 	xdmac_channel_enable(XDMAC, XDMA_CH_UART_RX);
412 #else
413     rx_buffer_ptr = data;
414     bytes_to_read = size;
415     usart_enable_interrupt(BOARD_USART, US_IER_RXRDY);
416 #endif
417 }
418 
419 #ifdef USE_XDMAC_FOR_USART
420 void XDMAC_Handler(void)
421 {
422 	uint32_t dma_status;
423 	dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_TX);
424 	if (dma_status & XDMAC_CIS_BIS) {
425 		if (tx_notify){
426 			tx_notify = 0;
427 			tx_done_handler();
428 		}
429 	}
430 	dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_RX);
431 	if (dma_status & XDMAC_CIS_BIS) {
432 		hal_uart_rts_high();
433 		if (rx_notify){
434 			rx_notify = 0;
435 			rx_done_handler();
436 		}
437 	}
438 }
439 #else
440 void USART_Handler(void)
441 {
442 
443 #ifdef DEBUG_PIN_2
444 	// ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_HIGH);
445 #endif
446 
447 	/* Read USART status. */
448 	uint32_t ul_status = usart_get_status(BOARD_USART);
449 
450 	// handle ready to send
451 	if(ul_status & US_IER_TXRDY) {
452 		if (bytes_to_write){
453 			// send next byte
454 			usart_write(BOARD_USART, *tx_buffer_ptr);
455 			tx_buffer_ptr++;
456 			bytes_to_write--;
457 		} else {
458 
459 			// done. disable tx ready interrupt to avoid starvation here
460 			usart_disable_interrupt(BOARD_USART, US_IER_TXRDY);
461 			if (tx_notify){
462 				tx_notify = 0;
463 				tx_done_handler();
464 			}
465 		}
466 	}
467 
468 	// handle byte available for read
469 	if (ul_status & US_IER_RXRDY) {
470 		if (bytes_to_read){
471 			uint32_t ch;
472 			usart_read(BOARD_USART, (uint32_t *)&ch);
473 			*rx_buffer_ptr++ = ch;
474 			bytes_to_read--;
475 			if (bytes_to_read == 0){
476 
477 #ifdef DEBUG_PIN_1
478 			ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_LOW);
479 #endif
480 
481 				// done. disable rx ready interrupt, raise RTS
482 				hal_uart_rts_high();
483 				usart_disable_interrupt(BOARD_USART, US_IER_RXRDY);
484 				if (rx_notify){
485 					rx_notify = 0;
486 					rx_done_handler();
487 				}
488 			}
489 		} else {
490 			// shoult not happen, disable irq anyway
491 			usart_disable_interrupt(BOARD_USART, US_IER_RXRDY);
492 		}
493 	}
494 #ifdef DEBUG_PIN_2
495 	// ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW);
496 #endif
497 
498 }
499 #endif
500 
501 void hal_tick_init()
502 {
503 	/* Configure systick for 1 ms */
504 	puts("Configure system tick to get 1ms tick period.\r");
505 	if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
506 		puts("-F- Systick configuration error\r");
507 		while (1);
508 	}
509 }
510 
511 void hal_tick_set_handler(void (*handler)(void)){
512 	if (handler == NULL){
513 		tick_handler = &dummy_handler;
514 		return;
515 	}
516 	tick_handler = handler;
517 }
518 
519 int  hal_tick_get_tick_period_in_ms(void){
520 	return 1;
521 }
522 
523 static const btstack_uart_block_t * uart_driver;
524 
525 static void phase2(int status){
526 
527     if (status){
528         printf("Download firmware failed\n");
529         return;
530     }
531 
532     printf("Phase 2: Main app\n");
533 
534     // init HCI
535     const hci_transport_t * transport = hci_transport_h4_instance(uart_driver);
536     hci_init(transport, (void*) &transport_config);
537     hci_set_chipset(btstack_chipset_atwilc3000_instance());
538 
539     // setup app
540     btstack_main(0, NULL);
541 }
542 
543 /**
544  *  \brief getting-started Application entry point.
545  *
546  *  \return Unused (ANSI-C compatibility).
547  */
548 // [main]
549 int main(void)
550 {
551 	/* Initialize the SAM system */
552 	sysclk_init();
553 	board_init();
554 
555 	/* Initialize the console uart */
556 	configure_console();
557 
558 	/* Output boot info */
559 	printf("BTstack on SAMV71 Xplained Ultra with ATWILC3000\n");
560 	printf("CPU %lu hz, peripheral clock %lu hz\n", sysclk_get_cpu_hz(), sysclk_get_peripheral_hz());
561 #ifdef USE_XDMAC_FOR_USART
562 	printf("Using XDMA for Bluetooth UART\n");
563 #else
564 	printf("Using IRQ driver for Bluetooth UART\n");
565 #endif
566 	printf("--\n");
567 
568 	// start with BTstack init - especially configure HCI Transport
569 	btstack_memory_init();
570 	btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
571 
572 	// enable full log output while porting
573     // hci_dump_init(hci_dump_embedded_stdout_get_instance());
574 
575 	// setup UART HAL + Run Loop integration
576 	uart_driver = btstack_uart_block_embedded_instance();
577 
578     // extract UART config from transport config, but disable flow control and use default baudrate
579     uart_config.baudrate    = HCI_DEFAULT_BAUDRATE;
580     uart_config.flowcontrol = 0;
581     uart_config.device_name = transport_config.device_name;
582     uart_driver->init(&uart_config);
583 
584     // phase #1 download firmware
585     printf("Phase 1: Download firmware\n");
586 
587     // phase #2 start main app
588     btstack_chipset_atwilc3000_download_firmware(uart_driver, transport_config.baudrate_init, transport_config.flowcontrol,  (const uint8_t *) firmware_ble, sizeof(firmware_ble), &phase2);
589 
590 	// go
591 	btstack_run_loop_execute();
592 
593 	// compiler happy
594 	while(1);
595 }
596 #ifdef __cplusplus
597 }
598 #endif
599