diff options
39 files changed, 1507 insertions, 116 deletions
| diff --git a/altosui/AltosConfig.java b/altosui/AltosConfig.java index 44c6239a..4b0edec0 100644 --- a/altosui/AltosConfig.java +++ b/altosui/AltosConfig.java @@ -393,8 +393,10 @@ public class AltosConfig implements ActionListener {  	}  	void abort() { -		serial_line.close(); -		serial_line = null; +		if (serial_line != null) { +			serial_line.close(); +			serial_line = null; +		}  		JOptionPane.showMessageDialog(owner,  					      String.format("Connection to \"%s\" failed",  							    device.toShortString()), diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 2c46da4a..306a396e 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -339,5 +339,3 @@ $(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi  	-rm -f $@  	makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi -publish: -	scp launch-sites.txt gag.com:public_html diff --git a/altosui/launch-sites.txt b/altosui/launch-sites.txt deleted file mode 100644 index de7955e0..00000000 --- a/altosui/launch-sites.txt +++ /dev/null @@ -1,13 +0,0 @@ -AHPRA BALLS:40.808333333333333:-119.15 -ARS Rio Rancho:35.33475:-106.75361 -HARA Bragg Farms:34.895875:-86.616211 -KLOUDBusters Rocket Pasture:37.167833333:-97.73975 -METRA Pine Island:41.31939:-74.47077 -NCR Pawnee:40.885955:-104.63793 -OPROC Discovery Bay:47.97808,-122.896383 -OROC Brothers:43.79949786336483:-120.6485810681392 -OROC Sheridan:45.044176:-123.314323 -QRS Cedar Grove:-27.8512283:152.9624000 -SCORE Hudson Ranch:38.155602777777778:-104.809119444444444 -Tripoli Colorado Hartsel:39.009247:-105.702338 -WAC Sportsman Club:47.815327777777778:-119.427186111111111 diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index 96659aaf..c82612a8 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -150,6 +150,9 @@ extern uint8_t	ao_cpu_sleep_disable;  #define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0) +#define ao_arch_block_interrupts()	cli() +#define ao_arch_release_interrupts()	sei() +  #define AO_TELESCIENCE_NUM_ADC	12  #endif /* _AO_ARCH_H_ */ diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index 7fdfad80..f2442eb6 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -153,6 +153,11 @@ extern AO_ROMCONFIG_SYMBOL(0x00a6) uint32_t ao_radio_cal;  #define ao_arch_cpu_idle()	(PCON = PCON_IDLE) +#define ao_arch_block_interrupts()	__asm clr ea __endasm +#define ao_arch_release_interrupts()	__asm setb ea __endasm +#define cli() ao_arch_block_interrupts() +#define sei() ao_arch_release_interrupts() +  #define ao_arch_restore_stack() {					\  		uint8_t stack_len;					\  		__data uint8_t *stack_ptr;				\ diff --git a/src/core/ao.h b/src/core/ao.h index e559e876..87e69e19 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -64,6 +64,7 @@  #define AO_PANIC_BT		11	/* Communications with bluetooth device failed */  #define AO_PANIC_STACK		12	/* Stack overflow */  #define AO_PANIC_SPI		13	/* SPI communication failure */ +#define AO_PANIC_CRASH		14	/* Processor crashed */  #define AO_PANIC_SELF_TEST_CC1120	0x40 | 1	/* Self test failure */  #define AO_PANIC_SELF_TEST_HMC5883	0x40 | 2	/* Self test failure */  #define AO_PANIC_SELF_TEST_MPU6000	0x40 | 3	/* Self test failure */ @@ -101,7 +102,7 @@ ao_delay(uint16_t ticks);  /* Set the ADC interval */  void -ao_timer_set_adc_interval(uint8_t interval) __critical; +ao_timer_set_adc_interval(uint8_t interval);  /* Timer interrupt */  void diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c index aa4f6961..64c95063 100644 --- a/src/core/ao_flight.c +++ b/src/core/ao_flight.c @@ -115,7 +115,7 @@ ao_flight(void)   			{  				/* Set pad mode - we can fly! */  				ao_flight_state = ao_flight_pad; -#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG +#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE  				/* Disable the USB controller in flight mode  				 * to save power  				 */ diff --git a/src/core/ao_ignite.c b/src/core/ao_ignite.c index c7829fc3..693b7c7a 100644 --- a/src/core/ao_ignite.c +++ b/src/core/ao_ignite.c @@ -21,10 +21,12 @@  __xdata struct ao_ignition ao_ignition[2];  void -ao_ignite(enum ao_igniter igniter) __critical +ao_ignite(enum ao_igniter igniter)  { +	cli();  	ao_ignition[igniter].request = 1;  	ao_wakeup(&ao_ignition); +	sei();  }  #ifndef AO_SENSE_DROGUE @@ -39,12 +41,12 @@ ao_igniter_status(enum ao_igniter igniter)  	__pdata int16_t value;  	__pdata uint8_t request, firing, fired; -	__critical { +	ao_arch_critical(  		ao_data_get(&packet);  		request = ao_ignition[igniter].request;  		fired = ao_ignition[igniter].fired;  		firing = ao_ignition[igniter].firing; -	} +		);  	if (firing || (request && !fired))  		return ao_igniter_active; @@ -79,7 +81,7 @@ ao_igniter_status(enum ao_igniter igniter)  #endif  void -ao_igniter_fire(enum ao_igniter igniter) __critical +ao_igniter_fire(enum ao_igniter igniter)  {  	ao_ignition[igniter].firing = 1;  	switch(ao_config.ignite_mode) { diff --git a/src/core/ao_list.h b/src/core/ao_list.h new file mode 100644 index 00000000..23cf1841 --- /dev/null +++ b/src/core/ao_list.h @@ -0,0 +1,213 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LIST_H_ +#define _AO_LIST_H_ + +#include <stddef.h> + +struct ao_list { +	struct ao_list	*next, *prev; +}; + +static inline void +ao_list_init(struct ao_list *list) +{ +	list->next = list->prev = list; +} + +static inline void +__ao_list_add(struct ao_list *list, struct ao_list *prev, struct ao_list *next) +{ +	next->prev = list; +	list->next = next; +	list->prev = prev; +	prev->next = list; +} + +/** + * Insert a new element after the given list head. The new element does not + * need to be initialised as empty list. + * The list changes from: + *      head → some element → ... + * to + *      head → new element → older element → ... + * + * Example: + * struct foo *newfoo = malloc(...); + * ao_list_add(&newfoo->entry, &bar->list_of_foos); + * + * @param entry The new element to prepend to the list. + * @param head The existing list. + */ +static inline void +ao_list_insert(struct ao_list *entry, struct ao_list *head) +{ +    __ao_list_add(entry, head, head->next); +} + +/** + * Append a new element to the end of the list given with this list head. + * + * The list changes from: + *      head → some element → ... → lastelement + * to + *      head → some element → ... → lastelement → new element + * + * Example: + * struct foo *newfoo = malloc(...); + * ao_list_append(&newfoo->entry, &bar->list_of_foos); + * + * @param entry The new element to prepend to the list. + * @param head The existing list. + */ +static inline void +ao_list_append(struct ao_list *entry, struct ao_list *head) +{ +    __ao_list_add(entry, head->prev, head); +} + +static inline void +__ao_list_del(struct ao_list *prev, struct ao_list *next) +{ +    next->prev = prev; +    prev->next = next; +} + +/** + * Remove the element from the list it is in. Using this function will reset + * the pointers to/from this element so it is removed from the list. It does + * NOT free the element itself or manipulate it otherwise. + * + * Using ao_list_del on a pure list head (like in the example at the top of + * this file) will NOT remove the first element from + * the list but rather reset the list as empty list. + * + * Example: + * ao_list_del(&foo->entry); + * + * @param entry The element to remove. + */ +static inline void +ao_list_del(struct ao_list *entry) +{ +    __ao_list_del(entry->prev, entry->next); +    ao_list_init(entry); +} + +/** + * Check if the list is empty. + * + * Example: + * ao_list_is_empty(&bar->list_of_foos); + * + * @return True if the list contains one or more elements or False otherwise. + */ +static inline uint8_t +ao_list_is_empty(struct ao_list *head) +{ +    return head->next == head; +} + +/** + * Returns a pointer to the container of this list element. + * + * Example: + * struct foo* f; + * f = container_of(&foo->entry, struct foo, entry); + * assert(f == foo); + * + * @param ptr Pointer to the struct ao_list. + * @param type Data type of the list element. + * @param member Member name of the struct ao_list field in the list element. + * @return A pointer to the data struct containing the list head. + */ +#define ao_container_of(ptr, type, member) \ +    (type *)((char *)(ptr) - offsetof(type, member)) + +/** + * Alias of ao_container_of + */ +#define ao_list_entry(ptr, type, member) \ +    ao_container_of(ptr, type, member) + +/** + * Retrieve the first list entry for the given list pointer. + * + * Example: + * struct foo *first; + * first = ao_list_first_entry(&bar->list_of_foos, struct foo, list_of_foos); + * + * @param ptr The list head + * @param type Data type of the list element to retrieve + * @param member Member name of the struct ao_list field in the list element. + * @return A pointer to the first list element. + */ +#define ao_list_first_entry(ptr, type, member) \ +    ao_list_entry((ptr)->next, type, member) + +/** + * Retrieve the last list entry for the given listpointer. + * + * Example: + * struct foo *first; + * first = ao_list_last_entry(&bar->list_of_foos, struct foo, list_of_foos); + * + * @param ptr The list head + * @param type Data type of the list element to retrieve + * @param member Member name of the struct ao_list field in the list element. + * @return A pointer to the last list element. + */ +#define ao_list_last_entry(ptr, type, member) \ +    ao_list_entry((ptr)->prev, type, member) + +/** + * Loop through the list given by head and set pos to struct in the list. + * + * Example: + * struct foo *iterator; + * ao_list_for_each_entry(iterator, &bar->list_of_foos, entry) { + *      [modify iterator] + * } + * + * This macro is not safe for node deletion. Use ao_list_for_each_entry_safe + * instead. + * + * @param pos Iterator variable of the type of the list elements. + * @param head List head + * @param member Member name of the struct ao_list in the list elements. + * + */ +#define ao_list_for_each_entry(pos, head, type, member)			\ +    for (pos = ao_container_of((head)->next, type, member);		\ +	 &pos->member != (head);					\ +	 pos = ao_container_of(pos->member.next, type, member)) + +/** + * Loop through the list, keeping a backup pointer to the element. This + * macro allows for the deletion of a list element while looping through the + * list. + * + * See ao_list_for_each_entry for more details. + */ +#define ao_list_for_each_entry_safe(pos, tmp, head, type, member)		\ +	for ((pos = ao_container_of((head)->next, type, member)),		\ +	     (tmp = ao_container_of(pos->member.next, type, member)); 		\ +	     &pos->member != (head);						\ +	     (pos = tmp), (tmp = ao_container_of(pos->member.next, type, member))) + +#endif /* _AO_LIST_H_ */ diff --git a/src/core/ao_mutex.c b/src/core/ao_mutex.c index c82a7d57..952ff462 100644 --- a/src/core/ao_mutex.c +++ b/src/core/ao_mutex.c @@ -22,11 +22,11 @@ ao_mutex_get(__xdata uint8_t *mutex) __reentrant  {  	if (*mutex == ao_cur_task->task_id)  		ao_panic(AO_PANIC_MUTEX); -	__critical { +	ao_arch_critical(  		while (*mutex)  			ao_sleep(mutex);  		*mutex = ao_cur_task->task_id; -	} +		);  }  void @@ -34,8 +34,8 @@ ao_mutex_put(__xdata uint8_t *mutex) __reentrant  {  	if (*mutex != ao_cur_task->task_id)  		ao_panic(AO_PANIC_MUTEX); -	__critical { +	ao_arch_critical(  		*mutex = 0;  		ao_wakeup(mutex); -	} +		);  } diff --git a/src/core/ao_packet.h b/src/core/ao_packet.h index f232a878..0eafd3b2 100644 --- a/src/core/ao_packet.h +++ b/src/core/ao_packet.h @@ -48,6 +48,7 @@ extern __xdata struct ao_task	ao_packet_task;  extern __xdata uint8_t ao_packet_enable;  extern __xdata uint8_t ao_packet_master_sleeping;  extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; +extern __xdata uint8_t ao_packet_restart;  void  ao_packet_send(void); @@ -62,7 +63,7 @@ void  ao_packet_putchar(char c) __reentrant;  char -ao_packet_pollchar(void) __critical; +ao_packet_pollchar(void);  #if PACKET_HAS_MASTER  /* ao_packet_master.c */ diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c index 3c0b471e..c29cd8fe 100644 --- a/src/core/ao_panic.c +++ b/src/core/ao_panic.c @@ -53,7 +53,8 @@ ao_panic(uint8_t reason)  	ao_cur_task = NULL;  	printf ("panic %d\n", reason);  #endif -	__critical for (;;) { +	ao_arch_block_interrupts(); +	for (;;) {  		ao_panic_delay(20);  		for (n = 0; n < 5; n++) {  			ao_led_on(AO_LED_PANIC); diff --git a/src/core/ao_sample_profile.c b/src/core/ao_sample_profile.c new file mode 100644 index 00000000..1d9ed414 --- /dev/null +++ b/src/core/ao_sample_profile.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_sample_profile.h> +#include <ao_task.h> + +#ifndef AO_SAMPLE_PROFILE_LOW_PC +#define AO_SAMPLE_PROFILE_LOW_PC	0x08000000 +#endif + +#ifndef AO_SAMPLE_PROFILE_HIGH_PC +#define AO_SAMPLE_PROFILE_HIGH_PC	(AO_SAMPLE_PROFILE_LOW_PC + 44 * 1024) +#endif + +#ifndef AO_SAMPLE_PROFILE_SHIFT +#define AO_SAMPLE_PROFILE_SHIFT		6 +#endif + +#define AO_SAMPLE_PROFILE_RANGE		(AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC) +#define AO_SAMPLE_PROFILE_NUM		(AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT) + +static uint16_t	prev_tick; +static uint16_t	samples[AO_SAMPLE_PROFILE_NUM]; +static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8]; +static uint16_t max_miss; +static uint32_t task, isr, os, idle; + +extern uint8_t ao_idle_loc; + +void +ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr) +{ +	uint16_t	delta = tick - prev_tick; + +	if (pc < AO_SAMPLE_PROFILE_LOW_PC) +		return; +	if (pc >= AO_SAMPLE_PROFILE_HIGH_PC) +		return; +	if (ao_cur_task) { +		uint8_t		*sp; +		int32_t		sp_delta; +		 +		asm("mov %0,sp" : "=&r" (sp)); +		sp_delta = sp - (uint8_t *) ao_cur_task->stack; +		if (-96 < sp_delta && sp_delta < 16) +			ao_panic(AO_PANIC_STACK); +	} + +	if (in_isr) +		isr += delta; +	else if (ao_cur_task) { +		ao_cur_task->ticks += delta; +		task += delta; +	} else if (pc == (uint32_t) &ao_idle_loc) +		idle += delta; +	else +		os += delta; + +	pc -= AO_SAMPLE_PROFILE_LOW_PC; +	pc >>= AO_SAMPLE_PROFILE_SHIFT; +	samples[pc] += delta; + +	if (delta > 1) +		missed[pc >> 3] |= (1 << (pc & 7)); +	if (delta > max_miss) +		max_miss = delta; +	prev_tick = tick; +} + +static void +ao_sample_profile_start(void) +{ +	prev_tick = ao_sample_profile_timer_start(); +} + +static void +ao_sample_profile_stop(void) +{ +	ao_sample_profile_timer_stop(); +} + +static void +ao_sample_profile_dump(void) +{ +	uint16_t	a; +	uint8_t		t; + +	printf ("task %6d\n", task); +	printf ("isr  %6d\n", isr); +	printf ("os   %6d\n", os); +	printf ("idle %6d\n", idle); +	printf ("irq blocked %d\n", max_miss); +	for (t = 0; t < ao_num_tasks; t++) +		printf ("task %6d %6d %6d %s\n", +			ao_tasks[t]->ticks, +			ao_tasks[t]->yields, +			ao_tasks[t]->max_run, +			ao_tasks[t]->name); +	for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) { +		if (samples[a]) +			printf ("%04x %c %u\n", +				(a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC, +				missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ', +				samples[a]); +	} +} + +static void +ao_sample_profile_clear(void) +{ +	int t; + +	task = isr = os = idle = 0; +	max_miss = 0; +	memset(samples, '\0', sizeof (samples)); +	memset(missed, '\0', sizeof (missed)); +	for (t = 0; t < ao_num_tasks; t++) { +		ao_tasks[t]->ticks = 0; +		ao_tasks[t]->yields = 0; +		ao_tasks[t]->max_run = 0; +	} +} + +static void +ao_sample_profile_cmd(void) +{ +	ao_cmd_white(); +	switch (ao_cmd_lex_c) { +	case '1': +		ao_sample_profile_start(); +		break; +	case '0': +		ao_sample_profile_stop(); +		break; +	case 'd': +		ao_sample_profile_dump(); +		break; +	case 'c': +		ao_sample_profile_clear(); +		break; +	default: +		ao_cmd_status = ao_cmd_syntax_error; +		break; +	} +} + +static __code struct ao_cmds ao_sample_profile_cmds[] = { +	{ ao_sample_profile_cmd,	"S <1 start,0 stop, d dump,c clear>\0Sample profile" }, +	{ 0, NULL } +}; + +void +ao_sample_profile_init(void) +{ +	ao_sample_profile_timer_init(); +	ao_cmd_register(&ao_sample_profile_cmds[0]); +	ao_sample_profile_clear(); +} diff --git a/src/core/ao_sample_profile.h b/src/core/ao_sample_profile.h new file mode 100644 index 00000000..dbc29d3d --- /dev/null +++ b/src/core/ao_sample_profile.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_SAMPLE_PROFILE_H_ +#define _AO_SAMPLE_PROFILE_H_ + +#include <ao_sample_profile_timer.h> + +void +ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr); + +void +ao_sample_profile_init(void); + +#endif /* _AO_SAMPLE_PROFILE_H_ */ diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 656b23c9..8cf66a23 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -96,21 +96,23 @@ flush(void)  __xdata uint8_t ao_stdin_ready;  char -getchar(void) __reentrant __critical +getchar(void) __reentrant  {  	char c; -	int8_t stdio = ao_cur_stdio; +	ao_arch_critical( +		int8_t stdio = ao_cur_stdio; -	for (;;) { -		c = ao_stdios[stdio].pollchar(); -		if (c != AO_READ_AGAIN) -			break; -		if (++stdio == ao_num_stdios) -			stdio = 0; -		if (stdio == ao_cur_stdio) -			ao_sleep(&ao_stdin_ready); -	} -	ao_cur_stdio = stdio; +		for (;;) { +			c = ao_stdios[stdio].pollchar(); +			if (c != AO_READ_AGAIN) +				break; +			if (++stdio == ao_num_stdios) +				stdio = 0; +			if (stdio == ao_cur_stdio) +				ao_sleep(&ao_stdin_ready); +		} +		ao_cur_stdio = stdio; +		);  	return c;  } diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 65654731..a11979f0 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -16,14 +16,26 @@   */  #include <ao.h> +#include <ao_task.h> +#if HAS_SAMPLE_PROFILE +#include <ao_sample_profile.h> +#endif +#if HAS_STACK_GUARD +#include <ao_mpu.h> +#endif + +#define DEBUG	0  #define AO_NO_TASK_INDEX	0xff  __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];  __data uint8_t ao_num_tasks; -__data uint8_t ao_cur_task_index;  __xdata struct ao_task *__data ao_cur_task; +#if !HAS_TASK_QUEUE +static __data uint8_t ao_cur_task_index; +#endif +  #ifdef ao_arch_task_globals  ao_arch_task_globals  #endif @@ -42,6 +54,225 @@ static inline void ao_check_stack(void) {  #define ao_check_stack()  #endif +#if HAS_TASK_QUEUE + +#define SLEEP_HASH_SIZE	17 + +static struct ao_list	run_queue; +static struct ao_list	alarm_queue; +static struct ao_list	sleep_queue[SLEEP_HASH_SIZE]; + +static void +ao_task_to_run_queue(struct ao_task *task) +{ +	ao_list_del(&task->queue); +	ao_list_append(&task->queue, &run_queue); +} + +static struct ao_list * +ao_task_sleep_queue(void *wchan) +{ +	return &sleep_queue[(uintptr_t) wchan % SLEEP_HASH_SIZE]; +} + +static void +ao_task_to_sleep_queue(struct ao_task *task, void *wchan) +{ +	ao_list_del(&task->queue); +	ao_list_append(&task->queue, ao_task_sleep_queue(wchan)); +} + +#if DEBUG +static void +ao_task_validate_alarm_queue(void) +{ +	struct ao_task	*alarm, *prev = NULL; +	int		i; + +	if (ao_list_is_empty(&alarm_queue)) +		return; +	ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) { +		if (prev) { +			if ((int16_t) (alarm->alarm - prev->alarm) < 0) { +				ao_panic(1); +			} +		} +		prev = alarm; +	} +	for (i = 0; i < ao_num_tasks; i++) { +		alarm = ao_tasks[i]; +		if (alarm->alarm) { +			if (ao_list_is_empty(&alarm->alarm_queue)) +				ao_panic(2); +		} else { +			if (!ao_list_is_empty(&alarm->alarm_queue)) +				ao_panic(3); +		} +	} +} +#else +#define ao_task_validate_alarm_queue() +#endif + +static void +ao_task_to_alarm_queue(struct ao_task *task) +{ +	struct ao_task	*alarm; +	ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) { +		if ((int16_t) (alarm->alarm - task->alarm) >= 0) { +			ao_list_insert(&task->alarm_queue, alarm->alarm_queue.prev); +			ao_task_validate_alarm_queue(); +			return; +		} +	} +	ao_list_append(&task->alarm_queue, &alarm_queue); +	ao_task_validate_alarm_queue(); +} + +static void +ao_task_from_alarm_queue(struct ao_task *task) +{ +	ao_list_del(&task->alarm_queue); +	ao_task_validate_alarm_queue(); +} + +static void +ao_task_init_queue(struct ao_task *task) +{ +	ao_list_init(&task->queue); +	ao_list_init(&task->alarm_queue); +} + +static void +ao_task_exit_queue(struct ao_task *task) +{ +	ao_list_del(&task->queue); +	ao_list_del(&task->alarm_queue); +} + +void +ao_task_check_alarm(uint16_t tick) +{ +	struct ao_task	*alarm, *next; +	int		i; + +	if (ao_num_tasks == 0) +		return; +	ao_list_for_each_entry_safe(alarm, next, &alarm_queue, struct ao_task, alarm_queue) { +		if ((int16_t) (tick - alarm->alarm) < 0) +			break; +		alarm->alarm = 0; +		ao_task_from_alarm_queue(alarm); +		ao_task_to_run_queue(alarm); +	} +} + +void +ao_task_init(void) +{ +	uint8_t	i; +	ao_list_init(&run_queue); +	ao_list_init(&alarm_queue); +	for (i = 0; i < SLEEP_HASH_SIZE; i++) +		ao_list_init(&sleep_queue[i]); +} + +#if DEBUG +static uint8_t +ao_task_validate_queue(struct ao_task *task) +{ +	uint32_t flags; +	struct ao_task *m; +	uint8_t ret = 0; +	struct ao_list *queue; + +	flags = ao_arch_irqsave(); +	if (task->wchan) { +		queue = ao_task_sleep_queue(task->wchan); +		ret |= 2; +	} else { +		queue = &run_queue; +		ret |= 4; +	} +	ao_list_for_each_entry(m, queue, struct ao_task, queue) { +		if (m == task) { +			ret |= 1; +			break; +		} +	} +	ao_arch_irqrestore(flags); +	return ret; +} + +static uint8_t +ao_task_validate_alarm(struct ao_task *task) +{ +	uint32_t	flags; +	struct ao_task	*m; +	uint8_t		ret = 0; + +	flags = ao_arch_irqsave(); +	if (task->alarm == 0) +		return 0xff; +	ao_list_for_each_entry(m, &alarm_queue, struct ao_task, alarm_queue) { +		if (m == task) +			ret |= 1; +		else { +			if (!(ret&1)) { +				if ((int16_t) (m->alarm - task->alarm) > 0) +					ret |= 2; +			} else { +				if ((int16_t) (task->alarm - m->alarm) > 0) +					ret |= 4; +			} +		} +	} +	ao_arch_irqrestore(flags); +	return ret; +} + + +static void +ao_task_validate(void) +{ +	uint8_t		i; +	struct ao_task	*task; +	uint8_t		ret; + +	for (i = 0; i < ao_num_tasks; i++) { +		task = ao_tasks[i]; +		ret = ao_task_validate_queue(task); +		if (!(ret & 1)) { +			if (ret & 2) +				printf ("sleeping task not on sleep queue %s %08x\n", +					task->name, task->wchan); +			else +				printf ("running task not on run queue %s\n", +					task->name); +		} +		ret = ao_task_validate_alarm(task); +		if (ret != 0xff) { +			if (!(ret & 1)) +				printf ("alarm task not on alarm queue %s %d\n", +					task->name, task->alarm); +			if (ret & 2) +				printf ("alarm queue has sooner entries after %s %d\n", +					task->name, task->alarm); +			if (ret & 4) +				printf ("alarm queue has later entries before %s %d\n", +					task->name, task->alarm); +		} +	} +} +#else +#define ao_task_validate() +#endif + +#else +#define ao_task_to_run_queue(task) +#define ao_task_to_alarm_queue(task) +#endif +  void  ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant  { @@ -56,7 +287,6 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam  		if (t == ao_num_tasks)  			break;  	} -	ao_tasks[ao_num_tasks++] = task;  	task->task_id = task_id;  	task->name = name;  	task->wchan = NULL; @@ -65,6 +295,14 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam  	 * to the start of the task  	 */  	ao_arch_init_stack(task, start); +	ao_arch_critical( +#if HAS_TASK_QUEUE +		ao_task_init_queue(task); +		ao_task_to_run_queue(task); +#endif +		ao_tasks[ao_num_tasks] = task; +		ao_num_tasks++; +		);  }  /* Task switching function. This must not use any stack variables */ @@ -73,10 +311,22 @@ ao_yield(void) ao_arch_naked_define  {  	ao_arch_save_regs(); +#if HAS_TASK_QUEUE +	if (ao_cur_task == NULL) +		ao_cur_task = ao_tasks[ao_num_tasks-1]; +#else  	if (ao_cur_task_index == AO_NO_TASK_INDEX)  		ao_cur_task_index = ao_num_tasks-1; +#endif  	else  	{ +#if HAS_SAMPLE_PROFILE +		uint16_t	tick = ao_sample_profile_timer_value(); +		uint16_t	run = tick - ao_cur_task->start; +		if (run > ao_cur_task->max_run) +			ao_cur_task->max_run = run; +		++ao_cur_task->yields; +#endif  		ao_arch_save_stack();  	} @@ -88,6 +338,24 @@ ao_yield(void) ao_arch_naked_define  	/* Find a task to run. If there isn't any runnable task,  	 * this loop will run forever, which is just fine  	 */ +#if HAS_TASK_QUEUE +	if (ao_cur_task->wchan == NULL) { +		uint32_t flags; +		flags = ao_arch_irqsave(); +		ao_task_to_run_queue(ao_cur_task); +		ao_arch_irqrestore(flags); +	} +	ao_cur_task = NULL; + +	for (;;) { +		ao_arch_memory_barrier(); +		if (!ao_list_is_empty(&run_queue)) +			break; +		ao_arch_cpu_idle(); +	} +		 +	ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue); +#else  	{  		__pdata uint8_t	ao_last_task_index = ao_cur_task_index;  		for (;;) { @@ -110,9 +378,16 @@ ao_yield(void) ao_arch_naked_define  			if (ao_cur_task_index == ao_last_task_index)  				ao_arch_cpu_idle();  		} +#if HAS_SAMPLE_PROFILE +		ao_cur_task->start = ao_sample_profile_timer_value(); +#endif  	} +#endif +#if HAS_STACK_GUARD +	ao_mpu_stack_guard(ao_cur_task->stack); +#endif  #if AO_CHECK_STACK -	cli(); +	ao_arch_block_interrupts();  	in_yield = 0;  #endif  	ao_arch_restore_stack(); @@ -121,7 +396,15 @@ ao_yield(void) ao_arch_naked_define  uint8_t  ao_sleep(__xdata void *wchan)  { +#if HAS_TASK_QUEUE +	uint32_t flags; +	flags = ao_arch_irqsave(); +#endif  	ao_cur_task->wchan = wchan; +#if HAS_TASK_QUEUE +	ao_task_to_sleep_queue(ao_cur_task, wchan); +	ao_arch_irqrestore(flags); +#endif  	ao_yield();  	if (ao_cur_task->wchan) {  		ao_cur_task->wchan = NULL; @@ -134,28 +417,62 @@ ao_sleep(__xdata void *wchan)  void  ao_wakeup(__xdata void *wchan)  { -	uint8_t	i; +#if HAS_TASK_QUEUE +	struct ao_task	*sleep, *next; +	struct ao_list	*sleep_queue; +	uint32_t	flags; -	ao_check_stack(); +	if (ao_num_tasks == 0) +		return; +	sleep_queue = ao_task_sleep_queue(wchan); +	flags = ao_arch_irqsave(); +	ao_list_for_each_entry_safe(sleep, next, sleep_queue, struct ao_task, queue) { +		if (sleep->wchan == wchan) { +			sleep->wchan = NULL; +			ao_task_to_run_queue(sleep); +		} +	} +	ao_arch_irqrestore(flags); +#else +	uint8_t	i;  	for (i = 0; i < ao_num_tasks; i++)  		if (ao_tasks[i]->wchan == wchan)  			ao_tasks[i]->wchan = NULL; +#endif +	ao_check_stack();  }  void  ao_alarm(uint16_t delay)  { +#if HAS_TASK_QUEUE +	uint32_t flags;  	/* Make sure we sleep *at least* delay ticks, which means adding  	 * one to account for the fact that we may be close to the next tick  	 */ +	flags = ao_arch_irqsave(); +#endif  	if (!(ao_cur_task->alarm = ao_time() + delay + 1))  		ao_cur_task->alarm = 1; +#if HAS_TASK_QUEUE +	ao_task_to_alarm_queue(ao_cur_task); +	ao_arch_irqrestore(flags); +#endif  }  void  ao_clear_alarm(void)  { +#if HAS_TASK_QUEUE +	uint32_t flags; + +	flags = ao_arch_irqsave(); +#endif  	ao_cur_task->alarm = 0; +#if HAS_TASK_QUEUE +	ao_task_from_alarm_queue(ao_cur_task); +	ao_arch_irqrestore(flags); +#endif  }  static __xdata uint8_t ao_forever; @@ -171,14 +488,22 @@ ao_delay(uint16_t ticks)  void  ao_exit(void)  { -	ao_arch_critical( -		uint8_t	i; -		ao_num_tasks--; -		for (i = ao_cur_task_index; i < ao_num_tasks; i++) -			ao_tasks[i] = ao_tasks[i+1]; -		ao_cur_task_index = AO_NO_TASK_INDEX; -		ao_yield(); -		); +	uint8_t	i; +	ao_arch_block_interrupts(); +	ao_num_tasks--; +#if HAS_TASK_QUEUE +	for (i = 0; i < ao_num_tasks; i++) +		if (ao_tasks[i] == ao_cur_task) +			break; +	ao_task_exit_queue(ao_cur_task); +#else +	i = ao_cur_task_index; +	ao_cur_task_index = AO_NO_TASK_INDEX; +#endif +	for (; i < ao_num_tasks; i++) +		ao_tasks[i] = ao_tasks[i+1]; +	ao_cur_task = NULL; +	ao_yield();  	/* we'll never get back here */  } @@ -194,12 +519,17 @@ ao_task_info(void)  		       task->name,  		       (int) task->wchan);  	} +#if HAS_TASK_QUEUE +	ao_task_validate(); +#endif  }  void  ao_start_scheduler(void)  { +#if !HAS_TASK_QUEUE  	ao_cur_task_index = AO_NO_TASK_INDEX; +#endif  	ao_cur_task = NULL;  	ao_yield();  } diff --git a/src/core/ao_task.h b/src/core/ao_task.h index 18edd866..b3f152a0 100644 --- a/src/core/ao_task.h +++ b/src/core/ao_task.h @@ -17,6 +17,9 @@  #ifndef _AO_TASK_H_  #define _AO_TASK_H_ +#if HAS_TASK_QUEUE +#include <ao_list.h> +#endif  /* An AltOS task */  struct ao_task { @@ -25,14 +28,26 @@ struct ao_task {  	ao_arch_task_members		/* any architecture-specific fields */  	uint8_t task_id;		/* unique id */  	__code char *name;		/* task name */ +#if HAS_TASK_QUEUE +	struct ao_list	queue; +	struct ao_list	alarm_queue; +#endif  	uint8_t	stack[AO_STACK_SIZE];	/* saved stack */ +#if HAS_SAMPLE_PROFILE +	uint32_t ticks; +	uint32_t yields; +	uint16_t start; +	uint16_t max_run; +#endif  }; -extern __xdata struct ao_task *__data ao_cur_task; -  #define AO_NUM_TASKS		16	/* maximum number of tasks */  #define AO_NO_TASK		0	/* no task id */ +extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; +extern __data uint8_t ao_num_tasks; +extern __xdata struct ao_task *__data ao_cur_task; +  /*   ao_task.c   */ @@ -65,6 +80,12 @@ ao_yield(void) ao_arch_naked_declare;  void  ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant; +#if HAS_TASK_QUEUE +/* Called on timer interrupt to check alarms */ +void +ao_task_check_alarm(uint16_t tick); +#endif +  /* Terminate the current task */  void  ao_exit(void); @@ -77,4 +98,11 @@ ao_task_info(void);  void  ao_start_scheduler(void); +#if HAS_TASK_QUEUE +void +ao_task_init(void); +#else +#define ao_task_init() +#endif +  #endif diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index f193ac8e..f3816047 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -312,18 +312,20 @@ __xdata struct ao_task ao_btm_task;  #endif  void -ao_btm_check_link() __critical +ao_btm_check_link()  { -	/* Check the pin and configure the interrupt detector to wait for the -	 * pin to flip the other way -	 */ -	if (BT_LINK_PIN) { -		ao_btm_connected = 0; -		PICTL |= BT_PICTL_ICON; -	} else { -		ao_btm_connected = 1; -		PICTL &= ~BT_PICTL_ICON; -	} +	ao_arch_critical( +		/* Check the pin and configure the interrupt detector to wait for the +		 * pin to flip the other way +		 */ +		if (BT_LINK_PIN) { +			ao_btm_connected = 0; +			PICTL |= BT_PICTL_ICON; +		} else { +			ao_btm_connected = 1; +			PICTL &= ~BT_PICTL_ICON; +		} +		);  }  void diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 2f9c296f..7428bead 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -21,6 +21,9 @@  #include <ao_fec.h>  #include <ao_packet.h> +#define AO_RADIO_MAX_RECV	sizeof(struct ao_packet) +#define AO_RADIO_MAX_SEND	sizeof(struct ao_packet) +  uint8_t ao_radio_wake;  uint8_t ao_radio_mutex;  uint8_t ao_radio_abort; @@ -559,18 +562,19 @@ ao_radio_test_cmd(void)  	}  } +static uint8_t	tx_data[(AO_RADIO_MAX_SEND + 4) * 2]; +  void  ao_radio_send(const void *d, uint8_t size)  {  	uint8_t		marc_status; -	static uint8_t	encode[256]; -	uint8_t		*e = encode; +	uint8_t		*e = tx_data;  	uint8_t		encode_len;  	uint8_t		this_len;  	uint8_t		started = 0;  	uint8_t		fifo_space; -	encode_len = ao_fec_encode(d, size, encode); +	encode_len = ao_fec_encode(d, size, tx_data);  	ao_radio_get(encode_len); @@ -611,8 +615,6 @@ ao_radio_send(const void *d, uint8_t size)  	ao_radio_put();  } -#define AO_RADIO_MAX_RECV	90 -  static uint8_t	rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];  static uint16_t	rx_data_count;  static uint16_t	rx_data_consumed; @@ -1026,6 +1028,7 @@ ao_radio_init(void)  	ao_radio_configured = 0;  	ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN)); +#if 0  	AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));  	for (i = 0; i < 10000; i++) {  		if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0) @@ -1034,6 +1037,7 @@ ao_radio_init(void)  	AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);  	if (i == 10000)  		ao_panic(AO_PANIC_SELF_TEST_CC1120); +#endif  	/* Enable the EXTI interrupt for the appropriate pin */  	ao_enable_port(AO_CC1120_INT_PORT); diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c index 077a40e6..ce0bcf4b 100644 --- a/src/drivers/ao_ms5607.c +++ b/src/drivers/ao_ms5607.c @@ -130,6 +130,7 @@ static uint32_t  ao_ms5607_get_sample(uint8_t cmd) {  	uint8_t	reply[3];  	uint8_t read; +	uint32_t loops;  	ao_ms5607_done = 0; @@ -141,10 +142,15 @@ ao_ms5607_get_sample(uint8_t cmd) {  #if AO_MS5607_PRIVATE_PINS  	ao_spi_put(AO_MS5607_SPI_INDEX);  #endif +//	loops = 0;  	cli(); -	while (!ao_ms5607_done) +	while (!ao_ms5607_done) { +//		loops++;  		ao_sleep((void *) &ao_ms5607_done); +	}  	sei(); +//	if (loops > 1) +//		printf ("ms5607 loops %d\n", loops);  #if AO_MS5607_PRIVATE_PINS  	stm_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, 1);  #else diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c index d813b25f..3c1e7a18 100644 --- a/src/drivers/ao_packet.c +++ b/src/drivers/ao_packet.c @@ -27,6 +27,7 @@ static __pdata uint8_t rx_seq;  __xdata struct ao_task	ao_packet_task;  __xdata uint8_t ao_packet_enable; +__xdata uint8_t ao_packet_restart;  #if PACKET_HAS_MASTER  __xdata uint8_t ao_packet_master_sleeping; @@ -106,7 +107,8 @@ ao_packet_recv(void)  		/* Check for incoming data at the next sequence and  		 * for an empty data buffer  		 */ -		if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && +		if ((ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) || +		     ao_packet_restart) &&  		    ao_packet_rx_used == ao_packet_rx_len) {  			/* Copy data to the receive data buffer and set up the @@ -126,6 +128,7 @@ ao_packet_recv(void)  			ao_wakeup(&ao_stdin_ready);  		}  	} +	ao_packet_restart = 0;  	/* If the other side has seen the latest data we queued,  	 * wake up any task waiting to send data and let them go again @@ -152,6 +155,9 @@ ao_packet_flush(void)  void  ao_packet_putchar(char c) __reentrant  { +	/* No need to block interrupts, all variables here +	 * are only manipulated in task context +	 */  	while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) {  #if PACKET_HAS_MASTER  		ao_packet_flush(); @@ -164,8 +170,11 @@ ao_packet_putchar(char c) __reentrant  }  char -ao_packet_pollchar(void) __critical +ao_packet_pollchar(void)  { +	/* No need to block interrupts, all variables here +	 * are only manipulated in task context +	 */  	if (!ao_packet_enable)  		return AO_READ_AGAIN; diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c index e97a6648..481232df 100644 --- a/src/drivers/ao_packet_master.c +++ b/src/drivers/ao_packet_master.c @@ -18,7 +18,7 @@  #include "ao.h"  static char -ao_packet_getchar(void) __critical +ao_packet_getchar(void)  {  	char c;  	while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { diff --git a/src/drivers/ao_packet_slave.c b/src/drivers/ao_packet_slave.c index fd5d443e..e45775cb 100644 --- a/src/drivers/ao_packet_slave.c +++ b/src/drivers/ao_packet_slave.c @@ -22,6 +22,7 @@ ao_packet_slave(void)  {  	ao_tx_packet.addr = ao_serial_number;  	ao_tx_packet.len = AO_PACKET_SYN; +	ao_packet_restart = 1;  	while (ao_packet_enable) {  		if (ao_packet_recv()) {  			ao_xmemcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 0e0534a5..7d6c7388 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -22,17 +22,27 @@ INC = \  	ao_mma655x.h \  	ao_cc1120_CC1120.h \  	ao_profile.h \ +	ao_task.h \  	ao_whiten.h \ -	stm32l.h +	ao_sample_profile.h \ +	ao_mpu.h \ +	stm32l.h \ +	Makefile  #  # Common AltOS sources  # +#	ao_hmc5883.c  #PROFILE=ao_profile.c  #PROFILE_DEF=-DAO_PROFILE=1 -#	ao_hmc5883.c +SAMPLE_PROFILE=ao_sample_profile.c \ +	ao_sample_profile_timer.c +SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +STACK_GUARD=ao_mpu_stm.c +STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \  	ao_interrupt.c \ @@ -80,13 +90,15 @@ ALTOS_SRC = \  	ao_packet.c \  	ao_companion.c \  	ao_pyro.c \ -	$(PROFILE) +	$(PROFILE) \ +	$(SAMPLE_PROFILE) \ +	$(STACK_GUARD)  PRODUCT=MegaMetrum-v0.1  PRODUCT_DEF=-DMEGAMETRUM  IDPRODUCT=0x0023 -CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g  PROGNAME=megametrum-v0.1  PROG=$(PROGNAME)-$(VERSION).elf diff --git a/src/megametrum-v0.1/ao_megametrum.c b/src/megametrum-v0.1/ao_megametrum.c index d3ae4690..cb1eb417 100644 --- a/src/megametrum-v0.1/ao_megametrum.c +++ b/src/megametrum-v0.1/ao_megametrum.c @@ -24,13 +24,24 @@  #include <ao_packet.h>  #include <ao_companion.h>  #include <ao_profile.h> +#if HAS_SAMPLE_PROFILE +#include <ao_sample_profile.h> +#endif  #include <ao_pyro.h> +#if HAS_STACK_GUARD +#include <ao_mpu.h> +#endif  int  main(void)  {  	ao_clock_init(); +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init();  	ao_serial_init();  	ao_led_init(LEDS_AVAILABLE);  	ao_led_on(AO_LED_GREEN); @@ -78,6 +89,9 @@ main(void)  #if AO_PROFILE  	ao_profile_init();  #endif +#if HAS_SAMPLE_PROFILE +	ao_sample_profile_init(); +#endif  	ao_start_scheduler();  	return 0; diff --git a/src/megametrum-v0.1/ao_pins.h b/src/megametrum-v0.1/ao_pins.h index e4c8c8fb..5ae80ac5 100644 --- a/src/megametrum-v0.1/ao_pins.h +++ b/src/megametrum-v0.1/ao_pins.h @@ -18,6 +18,8 @@  #ifndef _AO_PINS_H_  #define _AO_PINS_H_ +#define HAS_TASK_QUEUE		1 +  /* 8MHz High speed external crystal */  #define AO_HSE			8000000 diff --git a/src/stm-bringup/Makefile b/src/stm-bringup/Makefile index d45e836d..5cc94bd9 100644 --- a/src/stm-bringup/Makefile +++ b/src/stm-bringup/Makefile @@ -12,7 +12,7 @@ PDCLIB=/home/keithp/sat  C_LIB=$(PDCLIB)/lib/pdclib.a  C_INC=-I$(PDCLIB)/include -DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I../../src/stm $(C_INC) +DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../../src/stm $(C_INC)  # to run from SRAM  LD_FLAGS_RAM=-L../stm -Wl,-Taltos-ram.ld diff --git a/src/stm-bringup/ao.h b/src/stm-bringup/ao.h new file mode 100644 index 00000000..27204fae --- /dev/null +++ b/src/stm-bringup/ao.h @@ -0,0 +1,18 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define ao_panic(n)	for(;;); diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 87eda18b..0c3cfc91 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -43,7 +43,6 @@  #define __xdata  #define __code const  #define __reentrant -#define __critical  #define __interrupt(n)  #define __at(n) @@ -83,8 +82,29 @@ extern const uint32_t ao_radio_cal;  #define ao_arch_task_members\  	uint32_t *sp;			/* saved stack pointer */ -#define cli()	asm("cpsid i") -#define sei()	asm("cpsie i") +#define ao_arch_block_interrupts()	asm("cpsid i") +#define ao_arch_release_interrupts()	asm("cpsie i") + +#define cli()	ao_arch_block_interrupts() +#define sei()	ao_arch_release_interrupts() + +static uint32_t +ao_arch_irqsave(void) { +	uint32_t	primask; +	asm("mrs %0,primask" : "=&r" (primask)); +	ao_arch_block_interrupts(); +	return primask; +} + +static void +ao_arch_irqrestore(uint32_t primask) { +	asm("msr primask,%0" : : "r" (primask)); +} + +static void +ao_arch_memory_barrier() { +	asm volatile("" ::: "memory"); +}  #define ao_arch_init_stack(task, start) do {				\  		uint32_t	*sp = (uint32_t *) (task->stack + AO_STACK_SIZE); \ @@ -143,7 +163,7 @@ extern const uint32_t ao_radio_cal;  #define ao_arch_cpu_idle() do {			\ -		asm("wfi");		\ +		asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");	\  	} while (0)  #define ao_arch_restore_stack() do { \ diff --git a/src/stm/ao_beep_stm.c b/src/stm/ao_beep_stm.c index 37c30e25..4761fbfc 100644 --- a/src/stm/ao_beep_stm.c +++ b/src/stm/ao_beep_stm.c @@ -26,15 +26,6 @@ ao_beep(uint8_t beep)  	} else {  		stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN); -		stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | -				(0 << STM_TIM234_CR1_ARPE) | -				(STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | -				(0 << STM_TIM234_CR1_DIR) | -				(0 << STM_TIM234_CR1_OPM) | -				(0 << STM_TIM234_CR1_URS) | -				(0 << STM_TIM234_CR1_UDIS) | -				(0 << STM_TIM234_CR1_CEN)); -  		stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) |  				(STM_TIM234_CR2_MMS_RESET << STM_TIM234_CR2_MMS) |  				(0 << STM_TIM234_CR2_CCDS)); @@ -102,6 +93,9 @@ ao_beep(uint8_t beep)  				(0 << STM_TIM234_CR1_URS) |  				(0 << STM_TIM234_CR1_UDIS) |  				(1 << STM_TIM234_CR1_CEN)); + +		/* Update the values */ +		stm_tim3.egr = (1 << STM_TIM234_EGR_UG);  	}  } diff --git a/src/stm/ao_interrupt.c b/src/stm/ao_interrupt.c index 6b4a9700..a423d8b1 100644 --- a/src/stm/ao_interrupt.c +++ b/src/stm/ao_interrupt.c @@ -15,6 +15,7 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ +#include <ao.h>  #include "stm32l.h"  #include <string.h> @@ -28,7 +29,7 @@ extern char __bss_start__, __bss_end__;  void stm_halt_isr(void)  { -	for(;;); +	ao_panic(AO_PANIC_CRASH);  }  void stm_ignore_isr(void) diff --git a/src/stm/ao_mpu.h b/src/stm/ao_mpu.h new file mode 100644 index 00000000..cc6132a5 --- /dev/null +++ b/src/stm/ao_mpu.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_MPU_H_ +#define _AO_MPU_H_ + +extern uint32_t	ao_mpu_dregion; + +void +ao_mpu_stack_guard(void *stack); + +void +ao_mpu_init(void); + +#endif /* _AO_MPU_H_ */ diff --git a/src/stm/ao_mpu_stm.c b/src/stm/ao_mpu_stm.c new file mode 100644 index 00000000..969d7446 --- /dev/null +++ b/src/stm/ao_mpu_stm.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_mpu.h> + +static uint32_t	stm_mpu_dregion; + +void +ao_mpu_init(void) +{ +	uint32_t	region; + +	/* Check to see how many regions we have */ +	stm_mpu_dregion = (stm_mpu.typer >> STM_MPU_TYPER_DREGION) & STM_MPU_TYPER_DREGION_MASK; + +	/* No MPU at all */ +	if (stm_mpu_dregion == 0) +		return; + +	/* Disable MPU */ +	stm_mpu.cr = ((0 << STM_MPU_CR_PRIVDEFENA) | +		      (0 << STM_MPU_CR_HFNMIENA) | +		      (0 << STM_MPU_CR_ENABLE)); + +	/* Disable all regions */ +	for (region = 0; region < stm_mpu_dregion; region++) { +		/* Set the base address and RNR value */ +		stm_mpu.rbar = ((0 & (STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR)) | +				(1 << STM_MPU_RBAR_VALID) | +				(region << STM_MPU_RBAR_REGION)); + +		/* Disable this region */ +		stm_mpu.rasr = 0; +	} + +	region = 0; + +	/* Flash */ +	/* 0x00000000 - 0x1fffffff */ +	stm_mpu.rbar = (0x0000000 | +			(1 << STM_MPU_RBAR_VALID) | +			(region << STM_MPU_RBAR_REGION)); + +	stm_mpu.rasr = ((0 << STM_MPU_RASR_XN) | +			(STM_MPU_RASR_AP_RO_RO << STM_MPU_RASR_AP) | +			(5 << STM_MPU_RASR_TEX) | +			(0 << STM_MPU_RASR_C) | +			(1 << STM_MPU_RASR_B) | +			(0 << STM_MPU_RASR_S) | +			(0 << STM_MPU_RASR_SRD) | +			(28 << STM_MPU_RASR_SIZE) | +			(1 << STM_MPU_RASR_ENABLE)); +	region++; + +	/* Ram */ +	/* 0x20000000 - 0x3fffffff */ +	stm_mpu.rbar = (0x20000000 | +			(1 << STM_MPU_RBAR_VALID) | +			(region << STM_MPU_RBAR_REGION)); + +	stm_mpu.rasr = ((0 << STM_MPU_RASR_XN) | +			(STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) | +			(5 << STM_MPU_RASR_TEX) | +			(0 << STM_MPU_RASR_C) | +			(1 << STM_MPU_RASR_B) | +			(0 << STM_MPU_RASR_S) | +			(0 << STM_MPU_RASR_SRD) | +			(28 << STM_MPU_RASR_SIZE) | +			(1 << STM_MPU_RASR_ENABLE)); +	region++; + +	/* Peripherals */ + +	/* 0x4000000 - 0x7ffffff */ +	stm_mpu.rbar = (0x40000000 | +			(1 << STM_MPU_RBAR_VALID) | +			(region << STM_MPU_RBAR_REGION)); + +	stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) | +			(STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) | +			(2 << STM_MPU_RASR_TEX) | +			(0 << STM_MPU_RASR_C) | +			(0 << STM_MPU_RASR_B) | +			(0 << STM_MPU_RASR_S) | +			(0 << STM_MPU_RASR_SRD) | +			(29 << STM_MPU_RASR_SIZE) | +			(1 << STM_MPU_RASR_ENABLE)); +	region++; + +	/* 0x8000000 - 0xffffffff */ +	stm_mpu.rbar = (0x80000000 | +			(1 << STM_MPU_RBAR_VALID) | +			(region << STM_MPU_RBAR_REGION)); + +	stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) | +			(STM_MPU_RASR_AP_RW_RW << STM_MPU_RASR_AP) | +			(2 << STM_MPU_RASR_TEX) | +			(0 << STM_MPU_RASR_C) | +			(0 << STM_MPU_RASR_B) | +			(0 << STM_MPU_RASR_S) | +			(0 << STM_MPU_RASR_SRD) | +			(30 << STM_MPU_RASR_SIZE) | +			(1 << STM_MPU_RASR_ENABLE)); +	region++; + +	/* Enable MPU */ +	stm_mpu.cr = ((0 << STM_MPU_CR_PRIVDEFENA) | +		      (0 << STM_MPU_CR_HFNMIENA) | +		      (1 << STM_MPU_CR_ENABLE)); +} + +/* + * Protect the base of the stack from CPU access + */ + +void +ao_mpu_stack_guard(void *base) +{ +	uintptr_t	addr = (uintptr_t) base; + +	/* Round up to cover the lowest possible 32-byte region */ +	addr = (addr + ~(STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR)) & (STM_MPU_RBAR_ADDR_MASK << STM_MPU_RBAR_ADDR); + +	stm_mpu.rbar = addr | (1 << STM_MPU_RBAR_VALID) | (7 << STM_MPU_RBAR_REGION); +	stm_mpu.rasr = ((1 << STM_MPU_RASR_XN) | +			(STM_MPU_RASR_AP_NONE_NONE << STM_MPU_RASR_AP) | +			(5 << STM_MPU_RASR_TEX) | +			(0 << STM_MPU_RASR_C) | +			(1 << STM_MPU_RASR_B) | +			(0 << STM_MPU_RASR_S) | +			(0 << STM_MPU_RASR_SRD) | +			(4 << STM_MPU_RASR_SIZE) | +			(1 << STM_MPU_RASR_ENABLE)); +} diff --git a/src/stm/ao_sample_profile_timer.c b/src/stm/ao_sample_profile_timer.c new file mode 100644 index 00000000..d5af3a57 --- /dev/null +++ b/src/stm/ao_sample_profile_timer.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_sample_profile.h> + +struct stm_exception { +	uint32_t	r0; +	uint32_t	r1; +	uint32_t	r2; +	uint32_t	r3; +	uint32_t	r12; +	uint32_t	lr; +	uint32_t	pc; +	uint32_t	psr; +}; + +void +stm_tim10_isr(void) +{ +	struct stm_exception	*ex; + +	asm("mov %0,sp" : "=&r" (ex)); + +	stm_tim10.sr = 0; +	ao_sample_profile_point(ex->pc, stm_tim11.cnt, (ex->psr & 0xff) != 0); +} + +uint16_t +ao_sample_profile_timer_start(void) +{ +	/* Reset counts */ +	stm_tim11.cnt = 0; +	stm_tim10.cnt = 0; + +	/* Turn on timer 11 */ +	stm_tim11.cr1 = ((0 << STM_TIM1011_CR1_CKD) | +			 (0 << STM_TIM1011_CR1_ARPE) | +			 (1 << STM_TIM1011_CR1_URS) | +			 (0 << STM_TIM1011_CR1_UDIS) | +			 (1 << STM_TIM1011_CR1_CEN)); + +	/* Turn on timer 10 */ +	stm_tim10.cr1 = ((0 << STM_TIM1011_CR1_CKD) | +			 (0 << STM_TIM1011_CR1_ARPE) | +			 (1 << STM_TIM1011_CR1_URS) | +			 (0 << STM_TIM1011_CR1_UDIS) | +			 (1 << STM_TIM1011_CR1_CEN)); +	return stm_tim11.cnt; +} + +void +ao_sample_profile_timer_stop(void) +{ +	stm_tim10.cr1 = 0; +	stm_tim11.cr1 = 0; +} + +#if AO_APB2_PRESCALER > 1 +#define TIMER_91011_SCALER 2 +#else +#define TIMER_91011_SCALER 1 +#endif + +#define TIMER_10kHz	((AO_PCLK2 * TIMER_91011_SCALER) / 10000) +#define TIMER_1kHz	((AO_PCLK2 * TIMER_91011_SCALER) / 1000) + +void +ao_sample_profile_timer_init(void) +{ +	/* Turn on power for timer 10 and 11 */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM10EN) | (1 << STM_RCC_APB2ENR_TIM11EN); + +	/* Timer 10 is the 1kHz interrupt */ +	stm_tim10.cr1 = 0; +	stm_tim10.psc = TIMER_10kHz; +	stm_tim10.arr = 9; +	stm_tim10.cnt = 0; + +	/* Enable timer 10 update interrupt */ +	stm_tim10.dier = (1 << STM_TIM1011_DIER_UIE); + +	/* Poke timer to reload values */ +	stm_tim10.egr |= (1 << STM_TIM1011_EGR_UG); + +	/* Timer 11 is the 1kHz counter */ +	stm_tim11.cr1 = 0; +	stm_tim11.psc = TIMER_1kHz; +	stm_tim11.arr = 0xffff; +	stm_tim11.cnt = 0; + +	/* Disable interrupts for timer 11 */ +	stm_tim11.dier = 0; + +	/* Poke timer to reload values */ +	stm_tim11.egr |= (1 << STM_TIM1011_EGR_UG); + +	stm_tim10.sr = 0; +	stm_nvic_set_enable(STM_ISR_TIM10_POS); +	stm_nvic_set_priority(STM_ISR_TIM10_POS, AO_STM_NVIC_HIGH_PRIORITY); +} diff --git a/src/stm/ao_sample_profile_timer.h b/src/stm/ao_sample_profile_timer.h new file mode 100644 index 00000000..1da1bfb4 --- /dev/null +++ b/src/stm/ao_sample_profile_timer.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_SAMPLE_PROFILE_TIMER_H_ +#define _AO_SAMPLE_PROFILE_TIMER_H_ + +uint16_t +ao_sample_profile_timer_start(void); + +void +ao_sample_profile_timer_stop(void); + +void +ao_sample_profile_timer_init(void); + +#define ao_sample_profile_timer_value()	((uint16_t) stm_tim11.cnt) + +#endif /* _AO_SAMPLE_PROFILE_TIMER_H_ */ diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index f3011d3f..d69035f8 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -16,6 +16,7 @@   */  #include "ao.h" +#include <ao_task.h>  volatile __data AO_TICK_TYPE ao_tick_count; @@ -42,6 +43,9 @@ void stm_tim6_isr(void)  	if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {  		stm_tim6.sr = 0;  		++ao_tick_count; +#if HAS_TASK_QUEUE +		ao_task_check_alarm((uint16_t) ao_tick_count); +#endif  #if AO_DATA_ALL  		if (++ao_data_count == ao_data_interval) {  			ao_data_count = 0; @@ -56,10 +60,12 @@ void stm_tim6_isr(void)  #if HAS_ADC  void -ao_timer_set_adc_interval(uint8_t interval) __critical +ao_timer_set_adc_interval(uint8_t interval)  { -	ao_data_interval = interval; -	ao_data_count = 0; +	ao_arch_critical( +		ao_data_interval = interval; +		ao_data_count = 0; +		);  }  #endif diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 4f37a7d9..8e7dacc5 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -799,25 +799,23 @@ ao_usb_in_send(void)  	ao_usb_tx_count = 0;  } -/* Wait for a free IN buffer */ +/* Wait for a free IN buffer. Interrupts are blocked */  static void -ao_usb_in_wait(void) +_ao_usb_in_wait(void)  {  	for (;;) {  		/* Check if the current buffer is writable */  		if (ao_usb_tx_count < AO_USB_IN_SIZE)  			break; -		cli();  		/* Wait for an IN buffer to be ready */  		while (ao_usb_in_pending)  			ao_sleep(&ao_usb_in_pending); -		sei();  	}  }  void -ao_usb_flush(void) __critical +ao_usb_flush(void)  {  	if (!ao_usb_running)  		return; @@ -829,24 +827,25 @@ ao_usb_flush(void) __critical  	 * packet was full, in which case we now  	 * want to send an empty packet  	 */ +	ao_arch_block_interrupts();  	if (!ao_usb_in_flushed) {  		ao_usb_in_flushed = 1; -		cli();  		/* Wait for an IN buffer to be ready */  		while (ao_usb_in_pending)  			ao_sleep(&ao_usb_in_pending); -		sei();  		ao_usb_in_send();  	} +	ao_arch_release_interrupts();  }  void -ao_usb_putchar(char c) __critical __reentrant +ao_usb_putchar(char c)  {  	if (!ao_usb_running)  		return; -	ao_usb_in_wait(); +	ao_arch_block_interrupts(); +	_ao_usb_in_wait();  	ao_usb_in_flushed = 0;  	ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; @@ -854,10 +853,11 @@ ao_usb_putchar(char c) __critical __reentrant  	/* Send the packet when full */  	if (ao_usb_tx_count == AO_USB_IN_SIZE)  		ao_usb_in_send(); +	ao_arch_release_interrupts();  }  static void -ao_usb_out_recv(void) +_ao_usb_out_recv(void)  {  	ao_usb_out_avail = 0; @@ -888,7 +888,7 @@ _ao_usb_pollchar(void)  		/* Check to see if a packet has arrived */  		if (!ao_usb_out_avail)  			return AO_READ_AGAIN; -		ao_usb_out_recv(); +		_ao_usb_out_recv();  	}  	/* Pull a character out of the fifo */ @@ -900,27 +900,28 @@ char  ao_usb_pollchar(void)  {  	char	c; -	cli(); +	ao_arch_block_interrupts();  	c = _ao_usb_pollchar(); -	sei(); +	ao_arch_release_interrupts();  	return c;  }  char -ao_usb_getchar(void) __critical +ao_usb_getchar(void)  {  	char	c; -	cli(); +	ao_arch_block_interrupts();  	while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)  		ao_sleep(&ao_stdin_ready); -	sei(); +	ao_arch_release_interrupts();  	return c;  }  void  ao_usb_disable(void)  { +	ao_arch_block_interrupts();  	stm_usb.cntr = (1 << STM_USB_CNTR_FRES);  	stm_usb.istr = 0; @@ -932,6 +933,7 @@ ao_usb_disable(void)  	/* Disable the interface */  	stm_rcc.apb1enr &+ ~(1 << STM_RCC_APB1ENR_USBEN); +	ao_arch_release_interrupts();  }  void @@ -954,6 +956,8 @@ ao_usb_enable(void)  	 * pulled low and doesn't work at all  	 */ +	ao_arch_block_interrupts(); +  	/* Route interrupts */  	stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3);  	stm_nvic_set_enable(STM_ISR_USB_LP_POS); @@ -985,6 +989,8 @@ ao_usb_enable(void)  			(0 << STM_USB_CNTR_PDWN) |  			(0 << STM_USB_CNTR_FRES)); +	ao_arch_release_interrupts(); +  	for (t = 0; t < 1000; t++)  		ao_arch_nop();  	/* Enable USB pull-up */ diff --git a/src/stm/registers.ld b/src/stm/registers.ld index fd61e486..f8b224a2 100644 --- a/src/stm/registers.ld +++ b/src/stm/registers.ld @@ -46,5 +46,7 @@ stm_tim2   = 0x40000000;  stm_nvic   = 0xe000e100; +stm_mpu    = 0xe000ed90; +  /* calibration data in system memory */  stm_temp_cal = 0x1ff80078; diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 25f5af07..d953aee4 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -254,8 +254,138 @@ struct stm_tim {  };  extern struct stm_tim stm_tim9; -extern struct stm_tim stm_tim10; -extern struct stm_tim stm_tim11; + +struct stm_tim1011 { +	vuint32_t	cr1; +	uint32_t	unused_4; +	vuint32_t	smcr; +	vuint32_t	dier; +	vuint32_t	sr; +	vuint32_t	egr; +	vuint32_t	ccmr1; +	uint32_t	unused_1c; +	vuint32_t	ccer; +	vuint32_t	cnt; +	vuint32_t	psc; +	vuint32_t	arr; +	uint32_t	unused_30; +	vuint32_t	ccr1; +	uint32_t	unused_38; +	uint32_t	unused_3c; +	uint32_t	unused_40; +	uint32_t	unused_44; +	uint32_t	unused_48; +	uint32_t	unused_4c; +	vuint32_t	or; +}; + +extern struct stm_tim1011 stm_tim10; +extern struct stm_tim1011 stm_tim11; + +#define STM_TIM1011_CR1_CKD	8 +#define  STM_TIM1011_CR1_CKD_1		0 +#define  STM_TIM1011_CR1_CKD_2		1 +#define  STM_TIM1011_CR1_CKD_4		2 +#define  STM_TIM1011_CR1_CKD_MASK	3 +#define STM_TIM1011_CR1_ARPE	7 +#define STM_TIM1011_CR1_URS	2 +#define STM_TIM1011_CR1_UDIS	1 +#define STM_TIM1011_CR1_CEN	0 + +#define STM_TIM1011_SMCR_ETP	15 +#define STM_TIM1011_SMCR_ECE	14 +#define STM_TIM1011_SMCR_ETPS	12 +#define  STM_TIM1011_SMCR_ETPS_OFF	0 +#define  STM_TIM1011_SMCR_ETPS_2	1 +#define  STM_TIM1011_SMCR_ETPS_4	2 +#define  STM_TIM1011_SMCR_ETPS_8	3 +#define  STM_TIM1011_SMCR_ETPS_MASK	3 +#define STM_TIM1011_SMCR_ETF	8 +#define  STM_TIM1011_SMCR_ETF_NONE		0 +#define  STM_TIM1011_SMCR_ETF_CK_INT_2		1 +#define  STM_TIM1011_SMCR_ETF_CK_INT_4		2 +#define  STM_TIM1011_SMCR_ETF_CK_INT_8		3 +#define  STM_TIM1011_SMCR_ETF_DTS_2_6		4 +#define  STM_TIM1011_SMCR_ETF_DTS_2_8		5 +#define  STM_TIM1011_SMCR_ETF_DTS_4_6		6 +#define  STM_TIM1011_SMCR_ETF_DTS_4_8		7 +#define  STM_TIM1011_SMCR_ETF_DTS_8_6		8 +#define  STM_TIM1011_SMCR_ETF_DTS_8_8		9 +#define  STM_TIM1011_SMCR_ETF_DTS_16_5		10 +#define  STM_TIM1011_SMCR_ETF_DTS_16_6		11 +#define  STM_TIM1011_SMCR_ETF_DTS_16_8		12 +#define  STM_TIM1011_SMCR_ETF_DTS_32_5		13 +#define  STM_TIM1011_SMCR_ETF_DTS_32_6		14 +#define  STM_TIM1011_SMCR_ETF_DTS_32_8		15 +#define  STM_TIM1011_SMCR_ETF_MASK		15 + +#define STM_TIM1011_DIER_CC1E	1 +#define STM_TIM1011_DIER_UIE	0 + +#define STM_TIM1011_SR_CC1OF	9 +#define STM_TIM1011_SR_CC1IF	1 +#define STM_TIM1011_SR_UIF	0 + +#define STM_TIM1011_EGR_CC1G	1 +#define STM_TIM1011_EGR_UG	0 + +#define STM_TIM1011_CCMR1_OC1CE	7 +#define STM_TIM1011_CCMR1_OC1M	4 +#define  STM_TIM1011_CCMR1_OC1M_FROZEN			0 +#define  STM_TIM1011_CCMR1_OC1M_SET_1_ACTIVE_ON_MATCH	1 +#define  STM_TIM1011_CCMR1_OC1M_SET_1_INACTIVE_ON_MATCH	2 +#define  STM_TIM1011_CCMR1_OC1M_TOGGLE			3 +#define  STM_TIM1011_CCMR1_OC1M_FORCE_INACTIVE		4 +#define  STM_TIM1011_CCMR1_OC1M_FORCE_ACTIVE		5 +#define  STM_TIM1011_CCMR1_OC1M_PWM_MODE_1		6 +#define  STM_TIM1011_CCMR1_OC1M_PWM_MODE_2		7 +#define  STM_TIM1011_CCMR1_OC1M_MASK			7 +#define STM_TIM1011_CCMR1_OC1PE	3 +#define STM_TIM1011_CCMR1_OC1FE	2 +#define STM_TIM1011_CCMR1_CC1S	0 +#define  STM_TIM1011_CCMR1_CC1S_OUTPUT			0 +#define  STM_TIM1011_CCMR1_CC1S_INPUT_TI1		1 +#define  STM_TIM1011_CCMR1_CC1S_INPUT_TI2		2 +#define  STM_TIM1011_CCMR1_CC1S_INPUT_TRC		3 +#define  STM_TIM1011_CCMR1_CC1S_MASK			3 + +#define  STM_TIM1011_CCMR1_IC1F_NONE		0 +#define  STM_TIM1011_CCMR1_IC1F_CK_INT_2	1 +#define  STM_TIM1011_CCMR1_IC1F_CK_INT_4	2 +#define  STM_TIM1011_CCMR1_IC1F_CK_INT_8	3 +#define  STM_TIM1011_CCMR1_IC1F_DTS_2_6		4 +#define  STM_TIM1011_CCMR1_IC1F_DTS_2_8		5 +#define  STM_TIM1011_CCMR1_IC1F_DTS_4_6		6 +#define  STM_TIM1011_CCMR1_IC1F_DTS_4_8		7 +#define  STM_TIM1011_CCMR1_IC1F_DTS_8_6		8 +#define  STM_TIM1011_CCMR1_IC1F_DTS_8_8		9 +#define  STM_TIM1011_CCMR1_IC1F_DTS_16_5	10 +#define  STM_TIM1011_CCMR1_IC1F_DTS_16_6	11 +#define  STM_TIM1011_CCMR1_IC1F_DTS_16_8	12 +#define  STM_TIM1011_CCMR1_IC1F_DTS_32_5	13 +#define  STM_TIM1011_CCMR1_IC1F_DTS_32_6	14 +#define  STM_TIM1011_CCMR1_IC1F_DTS_32_8	15 +#define  STM_TIM1011_CCMR1_IC1F_MASK		15 +#define STM_TIM1011_CCMR1_IC1PSC	2 +#define  STM_TIM1011_CCMR1_IC1PSC_1		0 +#define  STM_TIM1011_CCMR1_IC1PSC_2		1 +#define  STM_TIM1011_CCMR1_IC1PSC_4		2 +#define  STM_TIM1011_CCMR1_IC1PSC_8		3 +#define  STM_TIM1011_CCMR1_IC1PSC_MASK		3 +#define STM_TIM1011_CCMR1_CC1S		0 + +#define STM_TIM1011_CCER_CC1NP		3 +#define STM_TIM1011_CCER_CC1P		1 +#define STM_TIM1011_CCER_CC1E		0 + +#define STM_TIM1011_OR_TI1_RMP_RI	3 +#define STM_TIM1011_ETR_RMP		2 +#define STM_TIM1011_TI1_RMP		0 +#define  STM_TIM1011_TI1_RMP_GPIO		0 +#define  STM_TIM1011_TI1_RMP_LSI		1 +#define  STM_TIM1011_TI1_RMP_LSE		2 +#define  STM_TIM1011_TI1_RMP_RTC		3 +#define  STM_TIM1011_TI1_RMP_MASK		3  /* Flash interface */ @@ -771,6 +901,63 @@ stm_nvic_get_priority(int irq) {  	return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);  } +struct stm_mpu { +	vuint32_t	typer; +	vuint32_t	cr; +	vuint32_t	rnr; +	vuint32_t	rbar; + +	vuint32_t	rasr; +	vuint32_t	rbar_a1; +	vuint32_t	rasr_a1; +	vuint32_t	rbar_a2; +	vuint32_t	rasr_a2; +	vuint32_t	rbar_a3; +	vuint32_t	rasr_a3; +}; + +extern struct stm_mpu stm_mpu; + +#define STM_MPU_TYPER_IREGION	16 +#define  STM_MPU_TYPER_IREGION_MASK	0xff +#define STM_MPU_TYPER_DREGION	8 +#define  STM_MPU_TYPER_DREGION_MASK	0xff +#define STM_MPU_TYPER_SEPARATE	0 + +#define STM_MPU_CR_PRIVDEFENA	2 +#define STM_MPU_CR_HFNMIENA	1 +#define STM_MPU_CR_ENABLE	0 + +#define STM_MPU_RNR_REGION	0 +#define STM_MPU_RNR_REGION_MASK		0xff + +#define STM_MPU_RBAR_ADDR	5 +#define STM_MPU_RBAR_ADDR_MASK		0x7ffffff + +#define STM_MPU_RBAR_VALID	4 +#define STM_MPU_RBAR_REGION	0 +#define STM_MPU_RBAR_REGION_MASK	0xf + +#define STM_MPU_RASR_XN		28 +#define STM_MPU_RASR_AP		24 +#define  STM_MPU_RASR_AP_NONE_NONE	0 +#define  STM_MPU_RASR_AP_RW_NONE	1 +#define  STM_MPU_RASR_AP_RW_RO		2 +#define  STM_MPU_RASR_AP_RW_RW		3 +#define  STM_MPU_RASR_AP_RO_NONE	5 +#define  STM_MPU_RASR_AP_RO_RO		6 +#define  STM_MPU_RASR_AP_MASK		7 +#define STM_MPU_RASR_TEX	19 +#define  STM_MPU_RASR_TEX_MASK		7 +#define STM_MPU_RASR_S		18 +#define STM_MPU_RASR_C		17 +#define STM_MPU_RASR_B		16 +#define STM_MPU_RASR_SRD	8 +#define  STM_MPU_RASR_SRD_MASK		0xff +#define STM_MPU_RASR_SIZE	1 +#define  STM_MPU_RASR_SIZE_MASK		0x1f +#define STM_MPU_RASR_ENABLE	0 +  #define isr(name) void stm_ ## name ## _isr(void);  isr(nmi) @@ -1438,6 +1625,13 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;  #define STM_TIM234_SR_CC1IF	1  #define STM_TIM234_SR_UIF	0 +#define STM_TIM234_EGR_TG	6 +#define STM_TIM234_EGR_CC4G	4 +#define STM_TIM234_EGR_CC3G	3 +#define STM_TIM234_EGR_CC2G	2 +#define STM_TIM234_EGR_CC1G	1 +#define STM_TIM234_EGR_UG	0 +  #define STM_TIM234_CCMR1_OC2CE	15  #define STM_TIM234_CCMR1_OC2M	12  #define  STM_TIM234_CCMR1_OC2M_FROZEN			0 | 
