diff --git a/.cproject b/.cproject index 4507fd4..e426cac 100755 --- a/.cproject +++ b/.cproject @@ -136,6 +136,7 @@ make + all true true @@ -143,6 +144,7 @@ make + clean true true @@ -150,7 +152,6 @@ make - distclean true false @@ -206,6 +207,7 @@ make + all true true @@ -237,6 +239,7 @@ make + distclean true false @@ -282,6 +285,22 @@ false true + + make + TEST_APP=pwm BOARD=stm32f4-discovery DEBUG=y + test + true + false + true + + + make + TEST_APP=pwm BOARD=stm32f4-discovery DEBUG=y + install + true + false + true + make APP=example_radio_rx BOARD=msp430-ccrf DEBUG=y @@ -308,6 +327,7 @@ make + all true true @@ -315,6 +335,7 @@ make + clean true true diff --git a/Makefile b/Makefile index 1fccb67..1f44a67 100755 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ doc: @$(MKDIR) $(DOC_DIR) (cat $(DOXYFILE) ; echo "INPUT=$(DOC_SRC)" ; echo "OUTPUT_DIRECTORY=$(DOC_DIR)") | doxygen - -test: check $(OBJECTS) $(ASM_OBJECTS) +test: $(OBJECTS) $(ASM_OBJECTS) @$(MKDIR) $(EXE_DIR) @$(MKDIR) $(MAP_DIR) @$(MKDIR) $(SIZE_DIR) diff --git a/config/make/stm32f4xx.mk b/config/make/stm32f4xx.mk index 4a9e9f3..252ca65 100644 --- a/config/make/stm32f4xx.mk +++ b/config/make/stm32f4xx.mk @@ -9,8 +9,8 @@ endif CROSS_COMPILE=arm-none-eabi- INCLUDES += \ - /usr/lib/arm-none-eabi/include \ - /usr/lib/gcc/arm-none-eabi/4.8/include + /opt/arm-2011.09/arm-none-eabi/include \ + /opt/arm-2011.09/lib/gcc/arm-none-eabi/4.6.1/include ifeq ($(DEBUG),y) OPTIM = 0 @@ -35,7 +35,6 @@ CFLAGS += \ -mfloat-abi=softfp \ -fdata-sections \ -ffunction-sections -# -D inline= -mthumb\ CPPCHECK_FLAGS += \ -D USE_STDPERIPH_DRIVER\ diff --git a/source/firmware/arch/stm32f4xx/board/stm32f4-discovery/include/stm32f4-discovery.h b/source/firmware/arch/stm32f4xx/board/stm32f4-discovery/include/stm32f4-discovery.h index 81faad3..d70a788 100755 --- a/source/firmware/arch/stm32f4xx/board/stm32f4-discovery/include/stm32f4-discovery.h +++ b/source/firmware/arch/stm32f4xx/board/stm32f4-discovery/include/stm32f4-discovery.h @@ -13,15 +13,18 @@ #include "driver.h" #include "gpio.h" +#include "pwm.h" #include "timer.h" #include "uart.h" #include "ringbuffer.h" #include "sys_tick.h" #include "stm32f4xx.h" #include "stm32f4_gpio.h" +#include "stm32f4_pwm.h" #include "stm32f4_uart.h" #include "stm32_sys_tick.h" + // SYSTEM TICK static const enum stm32_sys_tick_time_base stm23_sys_tick_time_base = STM32_SYS_TICK_TIME_BASE_MS; @@ -36,6 +39,62 @@ static const struct loki_timer timer_1 = { &timer_fp }; +// PWM CHANNEL 4 +/* apb1 clock = 84MHz */ +/* period_reg = src_clk / presc / cnt_clk */ +/* 4199 = 84MHZ / (0 + 1) / 20kHz - 1 */ +static const TIM_TimeBaseInitTypeDef timer_4_cfg = { + .TIM_RepetitionCounter = 0x0000, + .TIM_Prescaler = 0, + .TIM_ClockDivision = TIM_CKD_DIV1, + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = 4199 +}; + +static const TIM_OCInitTypeDef t4_output_compare_cfg = { + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Set, + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_Pulse = 0, +}; + +static const GPIO_InitTypeDef port_cfg = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + .GPIO_Speed = GPIO_Speed_100MHz, +}; + +static struct stm32f4_pwm str32f4_pwm = { + .timer = TIM4, + .timer_cfg = &timer_4_cfg, + .output_compare_cfg = &t4_output_compare_cfg, + .port = GPIOD, + .pin_src = GPIO_PinSource15, + .port_cfg = &port_cfg, + .channel = channel_4, +}; + +static const struct pwm pwm_ch4 = { + .arch_dep_device = &str32f4_pwm, + .fp = &stm32f4_pwm_fp, +}; + +#ifdef TEST_APP +static const struct driver pwm_4 = { +#else +const struct driver pwm_4 = { +#endif + DRIVER_TYPE_PWM, + &pwm_ch4, +}; + +// UART 1 static char console_linear_buffer[80]; static struct ringbuffer console_buffer = { console_linear_buffer, diff --git a/source/firmware/arch/stm32f4xx/driver/include/stm32f4_pwm.h b/source/firmware/arch/stm32f4xx/driver/include/stm32f4_pwm.h new file mode 100644 index 0000000..c46174f --- /dev/null +++ b/source/firmware/arch/stm32f4xx/driver/include/stm32f4_pwm.h @@ -0,0 +1,40 @@ +/* + * stm32f4_pwm.h + * + * Created on: Aug 9, 2016 + * Author: tkl + */ + +#ifndef SOURCE_FIRMWARE_ARCH_STM32F4XX_DRIVER_INCLUDE_STM32F4_PWM_H_ +#define SOURCE_FIRMWARE_ARCH_STM32F4XX_DRIVER_INCLUDE_STM32F4_PWM_H_ + +enum stm32f4_pwm_channel { + channel_1 = 1, + channel_2, + channel_3, + channel_4 +}; + +struct stm32f4_pwm { + TIM_TypeDef *timer; + const TIM_TimeBaseInitTypeDef *timer_cfg; + const TIM_OCInitTypeDef *output_compare_cfg; + const TIM_BDTRInitTypeDef *bdtr_cfg; + GPIO_TypeDef *port; + uint8_t pin_src; + const GPIO_InitTypeDef *port_cfg; + enum stm32f4_pwm_channel channel; +}; + + +int stm32f4_pwm_open(const void *pwm); +int stm32f4_pwm_close(const void *pwm); +int stm32f4_pwm_set_duty_cycle(const void *pwm, unsigned int duty_cycle_percent); + +static const struct pwm_fp stm32f4_pwm_fp = { + .open = stm32f4_pwm_open, + .close = stm32f4_pwm_close, + .set_duty_cycle = stm32f4_pwm_set_duty_cycle, +}; + +#endif /* SOURCE_FIRMWARE_ARCH_STM32F4XX_DRIVER_INCLUDE_STM32F4_PWM_H_ */ diff --git a/source/firmware/arch/stm32f4xx/driver/stm32f4_pwm.c b/source/firmware/arch/stm32f4xx/driver/stm32f4_pwm.c new file mode 100644 index 0000000..80faa5d --- /dev/null +++ b/source/firmware/arch/stm32f4xx/driver/stm32f4_pwm.c @@ -0,0 +1,113 @@ +/* + * stm32f4_pwm.c + * + * Created on: Aug 9, 2016 + * Author: tkl + */ +#include +#include + +#include "stm32f4xx.h" + +#include "pwm.h" +#include "stm32f4_pwm.h" + +struct stm32f4_pwm_object { + uint8_t used_channels; + uint32_t channel_1_max_period; + uint32_t channel_2_max_period; + uint32_t channel_3_max_period; + uint32_t channel_4_max_period; +}; + +static struct stm32f4_pwm_object stm32f4_pwm_object = { + .used_channels = 0, + .channel_1_max_period = 0, + .channel_2_max_period = 0, + .channel_3_max_period = 0, + .channel_4_max_period = 0, +}; + +int stm32f4_pwm_open(const void *pwm) +{ + if(NULL == pwm) + return -1; + struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm; + uint32_t clk_ahb_timer = 0, clk_ahb_gpio = 0; + uint8_t gpio_af_timer = 0; + if(this->timer == TIM4) { + clk_ahb_timer = RCC_APB1Periph_TIM4; + gpio_af_timer = GPIO_AF_TIM4; + } + RCC_APB1PeriphClockCmd(clk_ahb_timer, ENABLE); + if(this->port == GPIOD) { + clk_ahb_gpio = RCC_AHB1Periph_GPIOD; + } + RCC_AHB1PeriphClockCmd(clk_ahb_gpio, ENABLE); + GPIO_Init(this->port, (GPIO_InitTypeDef *)this->port_cfg); + GPIO_PinAFConfig(this->port, this->pin_src, gpio_af_timer); + + TIM_TimeBaseInit(this->timer, (TIM_TimeBaseInitTypeDef *)this->timer_cfg); + + switch(this->channel) { + case channel_1: + TIM_OC1Init(this->timer, (TIM_OCInitTypeDef *)this->output_compare_cfg); + TIM_OC1PreloadConfig(this->timer, TIM_OCPreload_Enable); + stm32f4_pwm_object.channel_1_max_period = this->timer_cfg->TIM_Period + 1; + break; + case channel_2: + TIM_OC2Init(this->timer, (TIM_OCInitTypeDef *)this->output_compare_cfg); + TIM_OC2PreloadConfig(this->timer, TIM_OCPreload_Enable); + stm32f4_pwm_object.channel_2_max_period = this->timer_cfg->TIM_Period + 1; + break; + case channel_3: + TIM_OC3Init(this->timer, (TIM_OCInitTypeDef *)this->output_compare_cfg); + TIM_OC3PreloadConfig(this->timer, TIM_OCPreload_Enable); + stm32f4_pwm_object.channel_3_max_period = this->timer_cfg->TIM_Period + 1; + break; + case channel_4: + TIM_OC4Init(this->timer, (TIM_OCInitTypeDef *)this->output_compare_cfg); + TIM_OC4PreloadConfig(this->timer, TIM_OCPreload_Enable); + stm32f4_pwm_object.channel_4_max_period = this->timer_cfg->TIM_Period + 1; + break; + } + TIM_ARRPreloadConfig(this->timer, ENABLE); + TIM_Cmd(this->timer, ENABLE); + stm32f4_pwm_object.used_channels++; + return 0; +} + +int stm32f4_pwm_close(const void *pwm) +{ + if(NULL == pwm) + return -1; + struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm; + stm32f4_pwm_set_duty_cycle(pwm, 0); + stm32f4_pwm_object.used_channels--; + if(stm32f4_pwm_object.used_channels == 0) { + TIM_Cmd(this->timer, DISABLE); + } + return 0; +} + +int stm32f4_pwm_set_duty_cycle(const void *pwm, unsigned int duty_cycle_percent) +{ + if(NULL == pwm) + return -1; + struct stm32f4_pwm *this = (struct stm32f4_pwm *)pwm; + switch(this->channel) { + case channel_1: + TIM_SetCompare1(this->timer, stm32f4_pwm_object.channel_1_max_period * duty_cycle_percent / 100); + break; + case channel_2: + TIM_SetCompare2(this->timer, stm32f4_pwm_object.channel_2_max_period * duty_cycle_percent / 100); + break; + case channel_3: + TIM_SetCompare3(this->timer, stm32f4_pwm_object.channel_3_max_period * duty_cycle_percent / 100); + break; + case channel_4: + TIM_SetCompare4(this->timer, stm32f4_pwm_object.channel_4_max_period * duty_cycle_percent / 100); + break; + } + return 0; +} diff --git a/source/firmware/kernel/driver/driver.c b/source/firmware/kernel/driver/driver.c index 06b4747..654c647 100644 --- a/source/firmware/kernel/driver/driver.c +++ b/source/firmware/kernel/driver/driver.c @@ -11,6 +11,7 @@ #include "adc.h" #include "gpio.h" #include "i2c.h" +#include "pwm.h" #include "rtc.h" #include "spi.h" #include "uart.h" @@ -30,6 +31,9 @@ int open(const struct driver *driver) case DRIVER_TYPE_I2C: ret = i2c_open((struct i2c *)(driver->device_driver)); break; + case DRIVER_TYPE_PWM: + ret = pwm_open((const struct pwm *)(driver->device_driver)); + break; case DRIVER_TYPE_RTC: ret = rtc_open((const struct rtc *)(driver->device_driver)); break; @@ -58,6 +62,9 @@ int close(const struct driver *driver) case DRIVER_TYPE_I2C: ret = i2c_close((struct i2c *)(driver->device_driver)); break; + case DRIVER_TYPE_PWM: + ret = pwm_close((const struct pwm *)(driver->device_driver)); + break; case DRIVER_TYPE_RTC: ret = rtc_close((const struct rtc *)(driver->device_driver)); break; @@ -88,6 +95,9 @@ int read(const struct driver *driver, char *buffer, int len) break; case DRIVER_TYPE_I2C: break; + case DRIVER_TYPE_PWM: + ret = -1; + break; case DRIVER_TYPE_RTC: break; case DRIVER_TYPE_SPI: @@ -118,6 +128,9 @@ int write(const struct driver *driver, const char *buffer, int len) break; case DRIVER_TYPE_I2C: break; + case DRIVER_TYPE_PWM: + ret = -1; + break; case DRIVER_TYPE_RTC: break; case DRIVER_TYPE_SPI: @@ -128,3 +141,31 @@ int write(const struct driver *driver, const char *buffer, int len) } return ret; } + +int ioctl(const struct driver *driver, unsigned int cmd, const void *data) +{ + int ret = -1; + if(NULL == driver) + return ret; + switch(driver->driver_type) { + case DRIVER_TYPE_ADC: + break; + case DRIVER_TYPE_GPIO: + break; + case DRIVER_TYPE_I2C: + break; + case DRIVER_TYPE_PWM: + if(cmd == IOCTL_PWM_SET_DUTY_CYCLE) { + unsigned int *duty = (unsigned int *)data; + pwm_set_duty_cycle((const struct pwm *)(driver->device_driver), *duty); + } + break; + case DRIVER_TYPE_RTC: + break; + case DRIVER_TYPE_SPI: + break; + case DRIVER_TYPE_UART: + break; + } + return ret; +} diff --git a/source/firmware/kernel/driver/include/pwm.h b/source/firmware/kernel/driver/include/pwm.h new file mode 100644 index 0000000..6d1d883 --- /dev/null +++ b/source/firmware/kernel/driver/include/pwm.h @@ -0,0 +1,35 @@ +/* + * pwm.h + * + * Created on: Aug 9, 2016 + * Author: tkl + */ + +#ifndef SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_PWM_H_ +#define SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_PWM_H_ + +//! \brief Function pointer to the open function. +typedef int (*pwm_fp_open_t)(const void*); + +//! \brief Function pointer to the close function. +typedef int (*pwm_fp_close_t)(const void*); + +//! \brief Function pointer to the read function. +typedef int (*pwm_fp_set_duty_cycle_t)(const void*, unsigned int duty_cycle_percent); + +struct pwm_fp { + const pwm_fp_open_t open; + const pwm_fp_close_t close; + const pwm_fp_set_duty_cycle_t set_duty_cycle; +}; + +struct pwm { + const void *arch_dep_device; //!< Architecture depended pwm device (i.e. stm32f10x_pwm_t). + const struct pwm_fp *fp; //!< Function pointer for the pwm driver access. +}; + +int pwm_open(const struct pwm *device); +int pwm_close(const struct pwm *device); +int pwm_set_duty_cycle(const struct pwm *device, unsigned int duty_cycle_percent); + +#endif /* SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_PWM_H_ */ diff --git a/source/firmware/kernel/driver/pwm.c b/source/firmware/kernel/driver/pwm.c new file mode 100644 index 0000000..a8e733e --- /dev/null +++ b/source/firmware/kernel/driver/pwm.c @@ -0,0 +1,33 @@ +/* + * pwm.c + * + * Created on: Aug 9, 2016 + * Author: tkl + */ + +#include +#include + +int pwm_open(const struct pwm *device) +{ + if(NULL == device) + return -1; + pwm_fp_open_t open = device->fp->open; + return open(device->arch_dep_device); +} + +int pwm_close(const struct pwm *device) +{ + if(NULL == device) + return -1; + pwm_fp_close_t close = device->fp->close; + return close(device->arch_dep_device); +} + +int pwm_set_duty_cycle(const struct pwm *device, unsigned int duty_cycle_percent) +{ + if(NULL == device) + return -1; + pwm_fp_set_duty_cycle_t set = device->fp->set_duty_cycle; + return set(device->arch_dep_device, duty_cycle_percent); +} diff --git a/source/firmware/kernel/interface/driver.h b/source/firmware/kernel/interface/driver.h index ee82abf..14923d9 100644 --- a/source/firmware/kernel/interface/driver.h +++ b/source/firmware/kernel/interface/driver.h @@ -8,10 +8,13 @@ #ifndef SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_DRIVER_H_ #define SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_DRIVER_H_ +#define IOCTL_PWM_SET_DUTY_CYCLE 0 + enum driver_type { DRIVER_TYPE_ADC, DRIVER_TYPE_GPIO, DRIVER_TYPE_I2C, + DRIVER_TYPE_PWM, DRIVER_TYPE_RTC, DRIVER_TYPE_SPI, DRIVER_TYPE_UART @@ -26,5 +29,6 @@ int open(const struct driver *driver); int close(const struct driver *driver); int read(const struct driver *driver, char *buffer, int len); int write(const struct driver *driver, const char *buffer, int len); +int ioctl(const struct driver *driver, unsigned int cmd, const void *data); #endif /* SOURCE_FIRMWARE_KERNEL_DRIVER_INCLUDE_DRIVER_H_ */ diff --git a/source/firmware/kernel/shell.c b/source/firmware/kernel/shell.c index 0cfdba2..3a832da 100644 --- a/source/firmware/kernel/shell.c +++ b/source/firmware/kernel/shell.c @@ -23,9 +23,9 @@ struct shell_object { struct shell_object shell_object; -#define RX_STACK_SIZE 256 -stack_t rx_stack[RX_STACK_SIZE]; -struct thread_context rx_thread; +#define TH_STACK_SIZE 256 +stack_t th_stack[TH_STACK_SIZE]; +struct thread_context th_ctx; static void parse(const char *buffer, unsigned int len) { @@ -71,7 +71,7 @@ int shell_init(const struct driver *shell_device) return -1; list_init(&shell_object.command_list); shell_object.shell_device = shell_device; - thread_create(&rx_thread, rx_stack, RX_STACK_SIZE, rx_func, NULL, THREAD_PRIO_LOW); + thread_create(&th_ctx, th_stack, TH_STACK_SIZE, rx_func, NULL, THREAD_PRIO_LOW); return 0; } diff --git a/source/test/pwm/main.c b/source/test/pwm/main.c new file mode 100644 index 0000000..e8b0418 --- /dev/null +++ b/source/test/pwm/main.c @@ -0,0 +1,48 @@ +/* + * main.c + * + * Created on: Aug 2, 2016 + * Author: tkl + */ + +#include + +#include "driver.h" +#include "board.h" +#include "stack.h" +#include "queue.h" +#include "kernel.h" +#include "driver.h" +#include "list.h" +#include "shell.h" + + +#define TH_STACK_SIZE 256 +stack_t th_stack[TH_STACK_SIZE]; +struct thread_context th_ctx; +static void th_func(void *arg) +{ + unsigned int duty = 0; + open(&pwm_4); + while(1) { + while(duty < 100) { + ioctl(&pwm_4, IOCTL_PWM_SET_DUTY_CYCLE, (const void *)&duty); + pwm_set_duty_cycle(&pwm_ch4, duty); + sleep_ms(10); + duty++; + } + while(duty > 0) { + ioctl(&pwm_4, IOCTL_PWM_SET_DUTY_CYCLE, (const void *)&duty); + sleep_ms(10); + duty--; + } + } +} + +int main(void) +{ + thread_create(&th_ctx, th_stack, TH_STACK_SIZE, th_func, NULL, THREAD_PRIO_LOW); + schedule_start(); + + return 0; +} diff --git a/source/test/pwm/pwm.mk b/source/test/pwm/pwm.mk new file mode 100644 index 0000000..0ce5cc1 --- /dev/null +++ b/source/test/pwm/pwm.mk @@ -0,0 +1,4 @@ +CHECK_FOLDER += source/test/pwm +SUB_FOLDER += source/test/pwm +INCLUDES += source/test/pwm +DOC_SRC += source/test/pwm diff --git a/source/test/test.mk b/source/test/test.mk index 910224c..e16b6ff 100644 --- a/source/test/test.mk +++ b/source/test/test.mk @@ -1,3 +1,6 @@ ifeq ($(TEST_APP), shell) include source/test/shell/shell.mk -endif \ No newline at end of file +endif +ifeq ($(TEST_APP), pwm) +include source/test/pwm/pwm.mk +endif