xref: /btstack/port/samv71-xplained-atwilc3000/main.c (revision 58a1b1bbd780fce065cc682a3cd9375e3ada0688)
1 /**
2  * \file
3  *
4  * \brief Getting Started Application.
5  *
6  * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 
44 /**
45  * \mainpage Getting Started Application
46  *
47  * \section Purpose
48  *
49  * BTstack port for SAM MCUs
50  *
51  * \section Requirements
52  *
53  * This package can be used with SAM evaluation kits.
54  *
55  * \section Description
56  *
57  *
58  * \section Usage
59  *
60  * -# Build the program and download it inside the evaluation board.
61  * -# On the computer, open and configure a terminal application
62  *    (e.g. HyperTerminal on Microsoft Windows) with these settings:
63  *   - 115200 bauds
64  *   - 8 bits of data
65  *   - No parity
66  *   - 1 stop bit
67  *   - No flow control
68  * -# Start the application.
69  *
70  */
71 
72 #include "asf.h"
73 #include "stdio_serial.h"
74 #include "conf_board.h"
75 #include "conf_clock.h"
76 
77 // BTstack
78 #include "btstack_run_loop.h"
79 #include "btstack_run_loop_embedded.h"
80 #include "btstack_debug.h"
81 #include "hci.h"
82 #include "hci_dump.h"
83 #include "btstack_chipset_atwilc3000.h"
84 #include "btstack_memory.h"
85 #include "classic/btstack_link_key_db.h"
86 
87 #include "hal_uart_dma.h"
88 #include "hal_cpu.h"
89 #include "hal_tick.h"
90 
91 extern int btstack_main(int argc, const char * argv[]);
92 
93 #define USE_XDMAC_FOR_USART
94 #define XDMA_CH_UART_TX   0
95 #define XDMA_CH_UART_RX  1
96 
97 #define STRING_EOL    "\r"
98 #define STRING_HEADER "-- Getting Started Example --\r\n" \
99 		"-- "BOARD_NAME" --\r\n" \
100 		"-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL
101 
102 /** All interrupt mask. */
103 #define ALL_INTERRUPT_MASK   0xffffffff
104 
105 static void dummy_handler(void){}
106 static void (*tick_handler)(void) = &dummy_handler;
107 
108 /** when porting to different setup, please
109  *  disable baudrate change (use 0 instead of 4000000)
110  *  and don't enable eHCILL mode (comment line below)
111  */
112 
113 // after HCI Reset, use 115200. Then increase baud rate to X.
114 static hci_transport_config_uart_t hci_transport_config = {
115 	HCI_TRANSPORT_CONFIG_UART,
116 	115200,
117 	4000000, // use 0 to skip baud rate change from 115200 to X for debugging purposes
118 	1,        // flow control
119 	NULL,
120 };
121 /// @cond 0
122 /**INDENT-OFF**/
123 #ifdef __cplusplus
124 extern "C" {
125 #endif
126 /**INDENT-ON**/
127 /// @endcond
128 
129 /**
130  *  \brief Handler for System Tick interrupt.
131  */
132 void SysTick_Handler(void)
133 {
134 	tick_handler();
135 }
136 
137 /**
138  *  Configure UART console.
139  */
140 // [main_console_configure]
141 static void configure_console(void)
142 {
143 	const usart_serial_options_t uart_serial_options = {
144 		.baudrate = CONF_UART_BAUDRATE,
145 #ifdef CONF_UART_CHAR_LENGTH
146 		.charlength = CONF_UART_CHAR_LENGTH,
147 #endif
148 		.paritytype = CONF_UART_PARITY,
149 #ifdef CONF_UART_STOP_BITS
150 		.stopbits = CONF_UART_STOP_BITS,
151 #endif
152 	};
153 
154 	/* Configure console UART. */
155 	sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
156 	stdio_serial_init(CONF_UART, &uart_serial_options);
157 }
158 
159 // [main_console_configure]
160 
161 /**
162  * \brief Wait for the given number of milliseconds (ticks
163  * generated by the SAM's microcontrollers's system tick).
164  *
165  * \param ul_dly_ticks  Delay to wait for, in milliseconds.
166  */
167 // [main_ms_delay]
168 static void mdelay(uint32_t delay_in_ms)
169 {
170 	// delay_ms(delay_in_ms);
171 	uint32_t time_to_wait = btstack_run_loop_get_time_ms() + delay_in_ms;
172 	while (btstack_run_loop_get_time_ms() < time_to_wait);
173 }
174 // [main_ms_delay]
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 // hal_cpu.h implementation
178 ////////////////////////////////////////////////////////////////////////////////
179 // hal_led.h implementation
180 #include "hal_led.h"
181 void hal_led_off(void);
182 void hal_led_on(void);
183 
184 void hal_led_off(void){
185 	// gpio_set_pin_low(GPIOA, GPIO_LED2);
186 }
187 void hal_led_on(void){
188 	// gpio_set_pin_high(GPIOA, GPIO_LED2);
189 }
190 void hal_led_toggle(void){
191 	// gpio_toggle_pin(GPIOA, GPIO_LED2);
192 }
193 
194 // hal_cpu.h implementation
195 #include "hal_cpu.h"
196 
197 void hal_cpu_disable_irqs(void){
198 	//__disable_irq();
199 }
200 
201 void hal_cpu_enable_irqs(void){
202 	// __enable_irq();
203 }
204 
205 void hal_cpu_enable_irqs_and_sleep(void){
206 	hal_led_off();
207 	// __enable_irq();
208 	// __asm__("wfe");	// go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag
209 
210 	// note: hal_uart_needed_during_sleep can be used to disable peripheral clock if it's not needed for a timer
211 	hal_led_on();
212 }
213 
214 
215 #ifndef USE_XDMAC_FOR_USART
216 // RX state
217 static volatile uint16_t  bytes_to_read = 0;
218 static volatile uint8_t * rx_buffer_ptr = 0;
219 
220 // TX state
221 static volatile uint16_t  bytes_to_write = 0;
222 static volatile uint8_t * tx_buffer_ptr = 0;
223 #endif
224 
225 // handlers
226 static void (*rx_done_handler)(void) = dummy_handler;
227 static void (*tx_done_handler)(void) = dummy_handler;
228 static void (*cts_irq_handler)(void) = dummy_handler;
229 
230 // @note While the Atmel SAM S7x data sheet states
231 // "The hardware handshaking feature enables an out-of-band flow control by automatic management
232 //  of the pins RTS and CTS.",
233 // I didn't see RTS going up automatically up, ever. So, at least for RTS, the automatic management
234 // is just a glorified GPIO pin control feature, which provides no benefit, but irritates a lot
235 
236 static void hal_uart_rts_high(void){
237 	BOARD_USART->US_CR = US_CR_RTSEN;
238 }
239 static void hal_uart_rts_low(void){
240 	BOARD_USART->US_CR = US_CR_RTSDIS;
241 }
242 
243 /**
244  */
245 void hal_uart_dma_init(void)
246 {
247 	// configure n_shutdown pin, and reset Bluetooth
248 	ioport_set_pin_dir(N_SHUTDOWN, IOPORT_DIR_OUTPUT);
249 	ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_LOW);
250 	mdelay(100);
251 	ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_HIGH);
252 	mdelay(500);
253 
254 	// configure Bluetooth USART
255 	const sam_usart_opt_t bluetooth_settings = {
256 		115200,
257 		US_MR_CHRL_8_BIT,
258 		US_MR_PAR_NO,
259 		US_MR_NBSTOP_1_BIT,
260 		US_MR_CHMODE_NORMAL,
261 		/* This field is only used in IrDA mode. */
262 		0
263 	};
264 
265 	/* Enable the peripheral clock in the PMC. */
266 	sysclk_enable_peripheral_clock(BOARD_ID_USART);
267 
268 	/* Configure USART mode. */
269 	usart_init_hw_handshaking(BOARD_USART, &bluetooth_settings, sysclk_get_peripheral_hz());
270 
271 	/* Disable all the interrupts. */
272 	usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK);
273 
274 	// RX not ready yet
275 	// usart_drive_RTS_pin_high(BOARD_USART);
276 
277 	/* Enable TX & RX function. */
278 	usart_enable_tx(BOARD_USART);
279 	usart_enable_rx(BOARD_USART);
280 
281 	/* Configure and enable interrupt of USART. */
282 	NVIC_EnableIRQ(USART_IRQn);
283 
284 #ifdef USE_XDMAC_FOR_USART
285 
286 	// setup XDMAC
287 
288 	/* Initialize and enable DMA controller */
289 	pmc_enable_periph_clk(ID_XDMAC);
290 
291 	/* Enable XDMA interrupt */
292 	NVIC_ClearPendingIRQ(XDMAC_IRQn);
293 	NVIC_SetPriority( XDMAC_IRQn ,1);
294 	NVIC_EnableIRQ(XDMAC_IRQn);
295 
296 	// Setup XDMA Channel for USART TX
297 	xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)&BOARD_USART->US_THR);
298 	xdmac_channel_set_config(XDMAC, XDMA_CH_UART_TX,
299 		XDMAC_CC_TYPE_PER_TRAN |
300 		XDMAC_CC_DSYNC_MEM2PER |
301 		XDMAC_CC_MEMSET_NORMAL_MODE |
302 		XDMAC_CC_MBSIZE_SINGLE |
303 		XDMAC_CC_DWIDTH_BYTE |
304 		XDMAC_CC_SIF_AHB_IF0 |
305 		XDMAC_CC_DIF_AHB_IF1 |
306 		XDMAC_CC_SAM_INCREMENTED_AM |
307 		XDMAC_CC_DAM_FIXED_AM |
308 		XDMAC_CC_CSIZE_CHK_1 |
309 		XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_TX)
310 	);
311 	xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_TX, 0);
312 	xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
313 	xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
314 	xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_TX, 0);
315 	xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_TX, 0);
316 	xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_TX);
317 	xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_TX, XDMAC_CIE_BIE);
318 
319 	// Setup XDMA Channel for USART RX
320 	xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)&BOARD_USART->US_RHR);
321 	xdmac_channel_set_config(XDMAC, XDMA_CH_UART_RX,
322 		XDMAC_CC_TYPE_PER_TRAN |
323 		XDMAC_CC_DSYNC_PER2MEM |
324 		XDMAC_CC_MEMSET_NORMAL_MODE |
325 		XDMAC_CC_MBSIZE_SINGLE |
326 		XDMAC_CC_DWIDTH_BYTE |
327 		XDMAC_CC_SIF_AHB_IF1 |
328 		XDMAC_CC_DIF_AHB_IF0 |
329 		XDMAC_CC_SAM_FIXED_AM |
330 		XDMAC_CC_DAM_INCREMENTED_AM |
331 		XDMAC_CC_CSIZE_CHK_1 |
332 		XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_RX)
333 	);
334 	xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_RX, 0);
335 	xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
336 	xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
337 	xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_RX, 0);
338 	xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_RX, 0);
339 	xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_RX);
340 	xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_RX, XDMAC_CIE_BIE);
341 #endif
342 }
343 
344 void hal_uart_dma_set_sleep(uint8_t sleep){
345 }
346 
347 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
348 	rx_done_handler = the_block_handler;
349 }
350 
351 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
352 	tx_done_handler = the_block_handler;
353 }
354 
355 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){
356 	cts_irq_handler = the_irq_handler;
357 }
358 
359 int  hal_uart_dma_set_baud(uint32_t baud){
360 	/* Disable TX & RX function. */
361 	usart_disable_tx(BOARD_USART);
362 	usart_disable_rx(BOARD_USART);
363 	uint32_t res = usart_set_async_baudrate(BOARD_USART, baud, sysclk_get_peripheral_hz());
364 	if (res){
365 		log_error("hal_uart_dma_set_baud library call failed");
366 	}
367 
368 	/* Enable TX & RX function. */
369 	usart_enable_tx(BOARD_USART);
370 	usart_enable_rx(BOARD_USART);
371 
372 	log_info("Bump baud rate");
373 
374 	return 0;
375 }
376 
377 void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
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     tx_buffer_ptr = (uint8_t *) data;
386     bytes_to_write = size;
387 	usart_enable_interrupt(BOARD_USART, US_IER_TXRDY);
388 #endif
389 }
390 
391 void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
392 
393 	hal_uart_rts_low();
394 
395 #ifdef USE_XDMAC_FOR_USART
396 	xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_RX);
397 	xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)data);
398 	xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_RX, size);
399 	xdmac_channel_enable(XDMAC, XDMA_CH_UART_RX);
400 #else
401     rx_buffer_ptr = data;
402     bytes_to_read = size;
403     usart_enable_interrupt(BOARD_USART, US_IER_RXRDY);
404 #endif
405 }
406 
407 #ifdef USE_XDMAC_FOR_USART
408 void XDMAC_Handler(void)
409 {
410 	uint32_t dma_status;
411 	dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_TX);
412 	if (dma_status & XDMAC_CIS_BIS) {
413 		tx_done_handler();
414 	}
415 	dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_RX);
416 	if (dma_status & XDMAC_CIS_BIS) {
417 		hal_uart_rts_high();
418 		rx_done_handler();
419 	}
420 }
421 #else
422 void USART_Handler(void)
423 {
424 	uint32_t ul_status;
425 	uint8_t uc_char;
426 
427 	/* Read USART status. */
428 	ul_status = usart_get_status(BOARD_USART);
429 
430 	// handle ready to send
431 	if(ul_status & US_IER_TXRDY) {
432 		if (bytes_to_write){
433 			// send next byte
434 			usart_write(BOARD_USART, *tx_buffer_ptr);
435 			tx_buffer_ptr++;
436 			bytes_to_write--;
437 		} else {
438 			// done. disable tx ready interrupt to avoid starvation here
439 			usart_disable_interrupt(BOARD_USART, US_IER_TXRDY);
440 			tx_done_handler();
441 		}
442 	}
443 
444 	// handle byte available for read
445 	if (ul_status & US_IER_RXRDY) {
446 		uint32_t ch;
447 		usart_read(BOARD_USART, (uint32_t *)&ch);
448 		*rx_buffer_ptr++ = ch;
449 		bytes_to_read--;
450 		if (bytes_to_read == 0){
451 			// done. disable rx ready interrupt, raise RTS
452 			hal_uart_rts_high();
453 			usart_disable_interrupt(BOARD_USART, US_IER_RXRDY);
454 			rx_done_handler();
455 		}
456 	}
457 }
458 #endif
459 
460 void hal_tick_init()
461 {
462 	/* Configure systick for 1 ms */
463 	puts("Configure system tick to get 1ms tick period.\r");
464 	if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
465 		puts("-F- Systick configuration error\r");
466 		while (1);
467 	}
468 }
469 
470 void hal_tick_set_handler(void (*handler)(void)){
471 	if (handler == NULL){
472 		tick_handler = &dummy_handler;
473 		return;
474 	}
475 	tick_handler = handler;
476 }
477 
478 int  hal_tick_get_tick_period_in_ms(void){
479 	return 1;
480 }
481 
482 
483 /**
484  *  \brief getting-started Application entry point.
485  *
486  *  \return Unused (ANSI-C compatibility).
487  */
488 // [main]
489 int main(void)
490 {
491 //! [main_step_sys_init]
492 	/* Initialize the SAM system */
493 	sysclk_init();
494 	board_init();
495 //! [main_step_sys_init]
496 
497 //! [main_step_console_init]
498 	/* Initialize the console uart */
499 	configure_console();
500 //! [main_step_console_init]
501 
502 	/* Output example information */
503 	puts(STRING_HEADER);
504 
505 	printf("CPU %lu hz, peripheral clock %lu hz\n", sysclk_get_cpu_hz(), sysclk_get_peripheral_hz());
506 
507 	// start with BTstack init - especially configure HCI Transport
508 	btstack_memory_init();
509 	btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
510 
511 	// enable full log output while porting
512 	// hci_dump_open(NULL, HCI_DUMP_STDOUT);
513 
514 	// init HCI
515 	// hci_init(hci_transport_h4_instance(), (void*) &hci_transport_config);
516 	// hci_set_chipset(btstack_chipset_cc256x_instance());
517 	// hci_set_link_key_db(btstack_link_key_db_memory_instance());
518 
519 	// enable eHCILL
520 	// bt_control_cc256x_enable_ehcill(1);
521 
522 	// hand over to btstack embedded code
523 	btstack_main(0, NULL);
524 
525 	// go
526 	btstack_run_loop_execute();
527 
528 	// compiler happy
529 	while(1);
530 }
531 // [main]
532 /// @cond 0
533 /**INDENT-OFF**/
534 #ifdef __cplusplus
535 }
536 #endif
537 /**INDENT-ON**/
538 /// @endcond
539