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