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