From: Nicolas D. <Ba...@us...> - 2011-03-19 16:32:54
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "krobot". The branch, master has been updated via cb716f5381d356396981452c97ed398603a58265 (commit) from 6409bfb8555556ae6d525498687b33f1ec8d125f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cb716f5381d356396981452c97ed398603a58265 Author: Nicolas Dandrimont <Nic...@cr...> Date: Fri Mar 18 23:52:18 2011 +0100 [USB_CAN/Firmware] Upgrade BeRTOS ----------------------------------------------------------------------- Changes: diff --git a/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_can.h b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_can.h index 827bc96..9d92690 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_can.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_can.h @@ -33,6 +33,7 @@ * \brief Configuration file for the CAN module. * * \author Nicolas Dandrimont <Nic...@cr...> + * */ #ifndef CFG_CAN_H @@ -54,4 +55,13 @@ */ #define CAN_LOG_FORMAT LOG_FMT_VERBOSE +/** + * CAN remapping + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "can_stm32_remaps" + * $WIZ$ supports = "stm32" + */ +#define CAN_STM32_REMAP CAN_STM32_PORTA + #endif /* CFG_CAN_H */ diff --git a/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_led_7seg.h b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_led_7seg.h new file mode 100644 index 0000000..d854b11 --- /dev/null +++ b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_led_7seg.h @@ -0,0 +1,80 @@ +/** + * \file cfg_led_7seg.h + * <!-- + * This file is part of BeRTOS. + * + * Bertos 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2010 Develer S.r.l. (http://www.develer.com/) + * --> + * + * \brief Configuration file for led 7 segment display. + * + * \author Fabio Bizzi <fb...@bi...> + * + * \addtogroup SevenSegDisplay 7 Segments LED Displays Driver + * \{ + * + */ + +#ifndef CFG_LED_7SEG_H +#define CFG_LED_7SEG_H + +/** + * Use a Common Cathode display. + * $WIZ$ type = "boolean" + */ +#define CONFIG_LED_7SEG_CCAT 0 + +/** + * Number of digit present in the LED display. + * $WIZ$ type = "int" + * $WIZ$ min = 1 + * $WIZ$ max = 8 + */ +#define CONFIG_LED_7SEG_DIGIT 4 + +/** + * Max lenght of the string to be displayed. + * $WIZ$ type = "int" + * $WIZ$ min = 16 + * $WIZ$ max = 255 + */ +#define CONFIG_LED_7SEG_STRLEN 255 + +/** + * Default scrolling speed (ms * CONFIG_LED_7SEG_RTIME). + * $WIZ$ type = "int" + */ +#define CONFIG_LED_7SEG_SSPEED 10 + +/** + * Default refresh time (ms). + * $WIZ$ type = "int" + */ +#define CONFIG_LED_7SEG_RTIME 5 + +#endif /* CFG_LED_7SEG_H */ + /** \} */ //defgroup drivers + diff --git a/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_pwm.h b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_pwm.h index 595189e..68d6283 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_pwm.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cfg/cfg_pwm.h @@ -53,4 +53,12 @@ */ #define PWM_LOG_FORMAT LOG_FMT_VERBOSE +/** + * Enable the OLD pwm API. + * Not recommended for new projects. + * + * $WIZ$ type = "boolean" + */ +#define CFG_PWM_ENABLE_OLD_API 1 + #endif /* CFG_PWM_H */ diff --git a/elec/boards/USB_CAN/Firmware/bertos/cfg/compiler.h b/elec/boards/USB_CAN/Firmware/bertos/cfg/compiler.h index ac60848..3a2f34c 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cfg/compiler.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cfg/compiler.h @@ -450,6 +450,9 @@ #endif #endif +/** User defined callback type */ +typedef void (*Hook)(void *); + /** Bulk storage large enough for both pointers or integers. */ typedef void * iptr_t; diff --git a/elec/boards/USB_CAN/Firmware/bertos/cfg/debug.h b/elec/boards/USB_CAN/Firmware/bertos/cfg/debug.h index efa26e1..ef6717c 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cfg/debug.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cfg/debug.h @@ -55,16 +55,21 @@ #include <cfg/os.h> #include <cfg/compiler.h> +#include "cfg/cfg_debug.h" /* CONFIG_KDEBUG_* */ /* * Defaults for rarely used config stuff. */ -#ifndef CONFIG_KDEBUG_DISABLE_TRACE -#define CONFIG_KDEBUG_DISABLE_TRACE 0 +#ifndef CONFIG_KDEBUG_TRACE +#define CONFIG_KDEBUG_TRACE 1 #endif -#ifndef CONFIG_KDEBUG_ASSERT_NO_TEXT -#define CONFIG_KDEBUG_ASSERT_NO_TEXT 0 +#ifndef CONFIG_KDEBUG_VERBOSE_ASSERT +#define CONFIG_KDEBUG_VERBOSE_ASSERT 1 +#endif + +#ifndef CONFIG_KDEBUG_WALLS +#define CONFIG_KDEBUG_WALLS 1 #endif #if defined(__doxygen__) @@ -127,7 +132,6 @@ */ #define DB(x) x - #include "cfg/cfg_debug.h" /* CONFIG_KDEBUG_ASSERT_NO_TEXT */ #include <cpu/attr.h> /* CPU_HARVARD */ /* These are implemented in drv/kdebug.c */ @@ -163,7 +167,7 @@ int __check_wall(long *wall, int size, const char *name, const char *file, int line); #endif /* !CPU_HARVARD */ - #if !CONFIG_KDEBUG_ASSERT_NO_TEXT + #if CONFIG_KDEBUG_VERBOSE_ASSERT /** * Assert a pre-condition on code. */ @@ -203,7 +207,7 @@ || ((void *)(p) >= (void *)CPU_RAM_START)) \ ? 0 : __invalid_ptr((p), #p, THIS_FILE, __LINE__))) - #if !CONFIG_KDEBUG_DISABLE_TRACE + #if CONFIG_KDEBUG_TRACE #define TRACE __trace(__func__) #define TRACEMSG(msg,...) __tracemsg(__func__, msg, ## __VA_ARGS__) #else @@ -211,19 +215,6 @@ #define TRACEMSG(...) do {} while(0) #endif - - /** - * \name Walls to detect data corruption - * \{ - */ - #define WALL_SIZE 8 - #define WALL_VALUE (long)0xABADCAFEL - #define DECLARE_WALL(name,size) long name[(size) / sizeof(long)]; - #define FWD_DECLARE_WALL(name,size) extern long name[(size) / sizeof(long)]; - #define INIT_WALL(name) __init_wall((name), countof(name)) - #define CHECK_WALL(name) __check_wall((name), countof(name), #name, THIS_FILE, __LINE__) - /*\}*/ - /** * Check that the given pointer actually points to an object * of the specified type. @@ -308,11 +299,6 @@ } #endif - #define DECLARE_WALL(name, size) /* nothing */ - #define FWD_DECLARE_WALL(name, size) /* nothing */ - #define INIT_WALL(name) do {} while (0) - #define CHECK_WALL(name) do {} while (0) - #define NEW_INSTANCE(CLASS) do {} while (0) #define DELETE_INSTANCE(CLASS) do {} while (0) #define ASSERT_ZERO_INSTANCES(CLASS) do {} while (0) @@ -336,6 +322,25 @@ #endif /* _DEBUG */ +#if CONFIG_KDEBUG_WALLS + /** + * \name Walls to detect data corruption + * \{ + */ + #define WALL_SIZE 8 + #define WALL_VALUE (long)0xABADCAFEL + #define DECLARE_WALL(name,size) long name[(size) / sizeof(long)]; + #define FWD_DECLARE_WALL(name,size) extern long name[(size) / sizeof(long)]; + #define INIT_WALL(name) __init_wall((name), countof(name)) + #define CHECK_WALL(name) __check_wall((name), countof(name), #name, THIS_FILE, __LINE__) + /*\}*/ +#else + #define DECLARE_WALL(name, size) /* nothing */ + #define FWD_DECLARE_WALL(name, size) /* nothing */ + #define INIT_WALL(name) do {} while (0) + #define CHECK_WALL(name) do {} while (0) +#endif + /** \} */ // defgroup debug #endif /* BERTOS_DEBUG_H */ diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.c index 397240e..c5780c3 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.c @@ -26,7 +26,7 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2008 Develer S.r.l. (http://www.develer.com/) + * Copyright 2011 Develer S.r.l. (http://www.develer.com/) * * --> * @@ -34,10 +34,11 @@ * \brief PWM hardware-specific implementation * * \author Daniele Basile <as...@de...> + * \author Francesco Sacchi <ba...@de...> */ +#include <drv/pwm.h> #include "pwm_at91.h" -#include "hw/pwm_map.h" #include <hw/hw_cpufreq.h> #include "cfg/cfg_pwm.h" @@ -50,201 +51,337 @@ #include <cfg/debug.h> #include <io/arm.h> +#include <cpu/irq.h> +#define PWM_HW_MAX_PRESCALER_STEP 10 +#define PWM_HW_MAX_PERIOD 0xFFFF -/** - * Register structure for pwm driver. - * This array content all data and register pointer - * to manage pwm peripheral device. - */ -static PwmChannel pwm_map[PWM_CNT] = -{ - {//PWM Channel 0 - .duty_zero = false, - .pol = false, - .pwm_pin = BV(PWM0), - .mode_reg = &PWM_CMR0, - .duty_reg = &PWM_CDTY0, - .period_reg = &PWM_CPRD0, - .update_reg = &PWM_CUPD0, - }, - {//PWM Channel 1 - .duty_zero = false, - .pol = false, - .pwm_pin = BV(PWM1), - .mode_reg = &PWM_CMR1, - .duty_reg = &PWM_CDTY1, - .period_reg = &PWM_CPRD1, - .update_reg = &PWM_CUPD1, - }, - {//PWM Channel 2 - .duty_zero = false, - .pol = false, - .pwm_pin = BV(PWM2), - .mode_reg = &PWM_CMR2, - .duty_reg = &PWM_CDTY2, - .period_reg = &PWM_CPRD2, - .update_reg = &PWM_CUPD2, - }, - {//PWM Channel 3 - .duty_zero = false, - .pol = false, - .pwm_pin = BV(PWM3), - .mode_reg = &PWM_CMR3, - .duty_reg = &PWM_CDTY3, - .period_reg = &PWM_CPRD3, - .update_reg = &PWM_CUPD3, - } -}; +#if CFG_PWM_ENABLE_OLD_API + #include "hw/pwm_map.h" + /** + * Register structure for pwm driver. + * This array content all data and register pointer + * to manage pwm peripheral device. + */ + static PwmChannel pwm_map[PWM_CNT] = + { + {//PWM Channel 0 + .duty_zero = false, + .pol = false, + .pwm_pin = BV(PWM0), + .mode_reg = &PWM_CMR0, + .duty_reg = &PWM_CDTY0, + .period_reg = &PWM_CPRD0, + .update_reg = &PWM_CUPD0, + }, + {//PWM Channel 1 + .duty_zero = false, + .pol = false, + .pwm_pin = BV(PWM1), + .mode_reg = &PWM_CMR1, + .duty_reg = &PWM_CDTY1, + .period_reg = &PWM_CPRD1, + .update_reg = &PWM_CUPD1, + }, + {//PWM Channel 2 + .duty_zero = false, + .pol = false, + .pwm_pin = BV(PWM2), + .mode_reg = &PWM_CMR2, + .duty_reg = &PWM_CDTY2, + .period_reg = &PWM_CPRD2, + .update_reg = &PWM_CUPD2, + }, + {//PWM Channel 3 + .duty_zero = false, + .pol = false, + .pwm_pin = BV(PWM3), + .mode_reg = &PWM_CMR3, + .duty_reg = &PWM_CDTY3, + .period_reg = &PWM_CPRD3, + .update_reg = &PWM_CUPD3, + } + }; -/** - * Get preiod from select channel - * - * \a dev channel - */ -pwm_period_t pwm_hw_getPeriod(PwmDev dev) -{ - return *pwm_map[dev].period_reg; -} -/** - * Set pwm waveform frequecy. - * - * \a freq in Hz - */ -void pwm_hw_setFrequency(PwmDev dev, uint32_t freq) -{ - uint32_t period = 0; + /** + * Get preiod from select channel + * + * \a dev channel + */ + pwm_period_t pwm_hw_getPeriod(PwmDev dev) + { + return *pwm_map[dev].period_reg; + } - for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++) + /** + * Set pwm waveform frequecy. + * + * \a freq in Hz + */ + void pwm_hw_setFrequency(PwmDev dev, uint32_t freq) { - period = CPU_FREQ / (BV(i) * freq); - LOG_INFO("period[%ld], prescale[%d]\n", period, i); - if ((period < PWM_HW_MAX_PERIOD) && (period != 0)) + uint32_t period = 0; + + for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++) { - //Clean previous channel prescaler, and set new - *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK; - *pwm_map[dev].mode_reg |= i; - //Set pwm period - *pwm_map[dev].period_reg = period; - break; + period = CPU_FREQ / (BV(i) * freq); + LOG_INFO("period[%ld], prescale[%d]\n", period, i); + if ((period < PWM_HW_MAX_PERIOD) && (period != 0)) + { + //Clean previous channel prescaler, and set new + *pwm_map[dev].mode_reg &= ~PWM_CPRE_MCK_MASK; + *pwm_map[dev].mode_reg |= i; + //Set pwm period + *pwm_map[dev].period_reg = period; + break; + } } + + LOG_INFO("PWM ch[%d] period[%ld]\n", dev, period); } - LOG_INFO("PWM ch[%d] period[%ld]\n", dev, period); -} + /** + * Set pwm duty cycle. + * + * \a duty value 0 - 2^16 + */ + void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty) + { + ASSERT(duty <= (uint16_t)*pwm_map[dev].period_reg); + -/** - * Set pwm duty cycle. - * - * \a duty value 0 - 2^16 - */ -void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty) -{ - ASSERT(duty <= (uint16_t)*pwm_map[dev].period_reg); + /* + * If polarity flag is true we must invert + * PWM polarity. + */ + if (pwm_map[dev].pol) + { + duty = (uint16_t)*pwm_map[dev].period_reg - duty; + LOG_INFO("Inverted duty[%d], pol[%d]\n", duty, pwm_map[dev].pol); + } + /* + * WARNING: is forbidden to write 0 to duty cycle value, + * and so for duty = 0 we must enable PIO and clear output! + */ + if (!duty) + { + PWM_PIO_CODR = pwm_map[dev].pwm_pin; + PWM_PIO_PER = pwm_map[dev].pwm_pin; + pwm_map[dev].duty_zero = true; + } + else + { + PWM_PIO_PDR = pwm_map[dev].pwm_pin; + PWM_PIO_ABSR = pwm_map[dev].pwm_pin; - /* - * If polarity flag is true we must invert - * PWM polarity. + *pwm_map[dev].update_reg = duty; + pwm_map[dev].duty_zero = false; + } + + PWM_ENA = BV(dev); + LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", dev, duty, *pwm_map[dev].period_reg); + } + + + /** + * Enable select pwm channel */ - if (pwm_map[dev].pol) + void pwm_hw_enable(PwmDev dev) { - duty = (uint16_t)*pwm_map[dev].period_reg - duty; - LOG_INFO("Inverted duty[%d], pol[%d]\n", duty, pwm_map[dev].pol); + if (!pwm_map[dev].duty_zero) + { + PWM_PIO_PDR = pwm_map[dev].pwm_pin; + PWM_PIO_ABSR = pwm_map[dev].pwm_pin; + } } - /* - * WARNING: is forbidden to write 0 to duty cycle value, - * and so for duty = 0 we must enable PIO and clear output! + /** + * Disable select pwm channel */ - if (!duty) + void pwm_hw_disable(PwmDev dev) { - PWM_PIO_CODR = pwm_map[dev].pwm_pin; - PWM_PIO_PER = pwm_map[dev].pwm_pin; - pwm_map[dev].duty_zero = true; + PWM_PIO_PER = pwm_map[dev].pwm_pin; } - else - { - PWM_PIO_PDR = pwm_map[dev].pwm_pin; - PWM_PIO_ABSR = pwm_map[dev].pwm_pin; - *pwm_map[dev].update_reg = duty; - pwm_map[dev].duty_zero = false; + /** + * Set PWM polarity to select pwm channel + */ + void pwm_hw_setPolarity(PwmDev dev, bool pol) + { + pwm_map[dev].pol = pol; + LOG_INFO("Set pol[%d]\n", pwm_map[dev].pol); } - PWM_ENA = BV(dev); - LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", dev, duty, *pwm_map[dev].period_reg); -} + /** + * Init pwm. + */ + void pwm_hw_init(void) + { + /* + * Init pwm: + * WARNING: is forbidden to write 0 to duty cycle value, + * and so for duty = 0 we must enable PIO and clear output! + * - clear PIO outputs + * - enable PIO outputs + * - Disable PIO and enable PWM functions + * - Power on PWM + */ + PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); + PWM_PIO_OER = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); + PWM_PIO_PDR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); + PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); + PMC_PCER |= BV(PWMC_ID); + + /* Disable all channels. */ + PWM_DIS = 0xFFFFFFFF; + /* Disable prescalers A and B */ + PWM_MR = 0; + + /* + * Set pwm mode: + * - set period alidned to left + * - set output waveform to start at high level + * - allow duty cycle modify at next period event + */ + for (int ch = 0; ch < PWM_CNT; ch++) + { + *pwm_map[ch].mode_reg = 0; + *pwm_map[ch].mode_reg = BV(PWM_CPOL); + } -/** - * Enable select pwm channel - */ -void pwm_hw_enable(PwmDev dev) -{ - if (!pwm_map[dev].duty_zero) - { - PWM_PIO_PDR = pwm_map[dev].pwm_pin; - PWM_PIO_ABSR = pwm_map[dev].pwm_pin; } -} -/** - * Disable select pwm channel - */ -void pwm_hw_disable(PwmDev dev) -{ - PWM_PIO_PER = pwm_map[dev].pwm_pin; -} +#else -/** - * Set PWM polarity to select pwm channel - */ -void pwm_hw_setPolarity(PwmDev dev, bool pol) -{ - pwm_map[dev].pol = pol; - LOG_INFO("Set pol[%d]\n", pwm_map[dev].pol); -} + typedef struct PwmChannelRegs + { + reg32_t CMR; + reg32_t CDTY; + reg32_t CPRD; + reg32_t CCNT; + reg32_t CUPD; + } PwmChannelRegs; -/** - * Init pwm. - */ -void pwm_hw_init(void) -{ /* - * Init pwm: - * WARNING: is forbidden to write 0 to duty cycle value, - * and so for duty = 0 we must enable PIO and clear output! - * - clear PIO outputs - * - enable PIO outputs - * - Disable PIO and enable PWM functions - * - Power on PWM + * Set pwm waveform frequecy. */ - PWM_PIO_CODR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); - PWM_PIO_OER = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); - PWM_PIO_PDR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); - PWM_PIO_ABSR = BV(PWM0) | BV(PWM1) | BV(PWM2) | BV(PWM3); - PMC_PCER |= BV(PWMC_ID); + void pwm_hw_setFrequency(Pwm *ctx, pwm_freq_t freq) + { + uint32_t period = 0; + + for(int i = 0; i <= PWM_HW_MAX_PRESCALER_STEP; i++) + { + period = CPU_FREQ / (BV(i) * freq); + LOG_INFO("period[%ld], prescale[%d]\n", period, i); + if ((period < PWM_HW_MAX_PERIOD) && (period != 0)) + { + //Clear previous channel prescaler, and set new + ctx->hw->base->CMR &= ~PWM_CPRE_MCK_MASK; + ctx->hw->base->CMR |= i; + //Set pwm period + ATOMIC( + ctx->hw->base->CPRD = period; + ctx->hw->base->CDTY = period; + ); + break; + } + } + + LOG_INFO("PWM ch[%d] period[%ld]\n", ctx->ch, period); + } - /* Disable all channels. */ - PWM_DIS = 0xFFFFFFFF; - /* Disable prescalers A and B */ - PWM_MR = 0; + pwm_hwreg_t pwm_hw_getPeriod(Pwm *ctx) + { + return ctx->hw->base->CPRD; + } /* - * Set pwm mode: - * - set period alidned to left - * - set output waveform to start at high level - * - allow duty cycle modify at next period event + * Set pwm duty cycle. + * + * duty value 0 - (2^16 - 1) */ - for (int ch = 0; ch < PWM_CNT; ch++) + void pwm_hw_setDuty(Pwm *ctx, pwm_hwreg_t hw_duty) { - *pwm_map[ch].mode_reg = 0; - *pwm_map[ch].mode_reg = BV(PWM_CPOL); + ASSERT(hw_duty <= ctx->hw->base->CPRD); + + /* + * WARNING: is forbidden to write 0 or 1 to duty cycle value, + * and so for duty < 2 we must enable PIO and clear output! + */ + if (hw_duty < 2) + { + hw_duty = 2; + PWM_PIO_PER = ctx->hw->pwm_pin; + } + else + PWM_PIO_PDR = ctx->hw->pwm_pin; + + ctx->hw->base->CUPD = hw_duty; + LOG_INFO("PWM ch[%d] duty[%d], period[%ld]\n", ctx->ch, hw_duty, ctx->hw->base->CPRD); } -} + static PwmHardware pwm_channels[] = + { + {//PWM Channel 0 + .pwm_pin = BV(PWM0), + .base = (volatile PwmChannelRegs *)&PWM_CMR0, + }, + {//PWM Channel 1 + .pwm_pin = BV(PWM1), + .base = (volatile PwmChannelRegs *)&PWM_CMR1, + }, + {//PWM Channel 2 + .pwm_pin = BV(PWM2), + .base = (volatile PwmChannelRegs *)&PWM_CMR2, + }, + {//PWM Channel 3 + .pwm_pin = BV(PWM3), + .base = (volatile PwmChannelRegs *)&PWM_CMR3, + }, + }; + + /* + * Init pwm. + */ + void pwm_hw_init(Pwm *ctx, unsigned ch) + { + + ctx->hw = &pwm_channels[ch]; + + /* + * Init pwm: + * - clear PIO outputs + * - enable PIO outputs + * - Enable PWM functions + * - Power on PWM + */ + PWM_PIO_CODR = ctx->hw->pwm_pin; + PWM_PIO_OER = ctx->hw->pwm_pin; + PWM_PIO_PER = ctx->hw->pwm_pin; + PWM_PIO_ABSR = ctx->hw->pwm_pin; + + PMC_PCER |= BV(PWMC_ID); + + /* Disable prescalers A and B */ + PWM_MR = 0; + + /* + * Set pwm mode: + * WARNING: is forbidden to write 0 or 1 to duty cycle value, + * and so for start we set duty to 2. + * Also: + * - set period aligned to left + * - set output waveform to start at high level + * - allow duty cycle modify at next period event + */ + ctx->hw->base->CDTY = 2; + ctx->hw->base->CMR = BV(PWM_CPOL); + PWM_ENA = BV(ch); + } +#endif diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.h b/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.h index 5d36289..403b9f5 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/arm/drv/pwm_at91.h @@ -40,44 +40,64 @@ #ifndef DRV_PWM_AT91_H #define DRV_PWM_AT91_H -#include "hw/pwm_map.h" - #include <cfg/compiler.h> #include <cfg/macros.h> +#include "cfg/cfg_pwm.h" + #include <io/arm.h> +#if CFG_PWM_ENABLE_OLD_API -#define PWM_HW_MAX_PRESCALER_STEP 10 -#define PWM_HW_MAX_PERIOD 0xFFFF + #include "hw/pwm_map.h" -/** - * Type definition for pwm period. - */ -typedef uint16_t pwm_period_t; + /** + * Type definition for pwm period. + */ + typedef uint16_t pwm_period_t; -/** - * Structur definition for pwm driver. - */ -typedef struct PwmChannel -{ - bool duty_zero; ///< True if duty cyle is zero, false otherwise. - bool pol; ///< PWM polarty flag. - int pwm_pin; ///< PWM pin. - reg32_t *mode_reg; ///< PWM mode register. - reg32_t *duty_reg; ///< PWM duty cycle register. - reg32_t *period_reg; ///< PWM periodic register. - reg32_t *update_reg; ///< Update setting register for PWM. - -} PwmChannel; - - -void pwm_hw_init(void); -void pwm_hw_setFrequency(PwmDev dev, uint32_t freq); -void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty); -void pwm_hw_disable(PwmDev dev); -void pwm_hw_enable(PwmDev dev); -void pwm_hw_setPolarity(PwmDev dev, bool pol); -pwm_period_t pwm_hw_getPeriod(PwmDev dev); + /** + * Structur definition for pwm driver. + */ + typedef struct PwmChannel + { + bool duty_zero; ///< True if duty cyle is zero, false otherwise. + bool pol; ///< PWM polarty flag. + int pwm_pin; ///< PWM pin. + reg32_t *mode_reg; ///< PWM mode register. + reg32_t *duty_reg; ///< PWM duty cycle register. + reg32_t *period_reg; ///< PWM periodic register. + reg32_t *update_reg; ///< Update setting register for PWM. + + } PwmChannel; + + + void pwm_hw_init(void); + void pwm_hw_setFrequency(PwmDev dev, uint32_t freq); + void pwm_hw_setDutyUnlock(PwmDev dev, uint16_t duty); + void pwm_hw_disable(PwmDev dev); + void pwm_hw_enable(PwmDev dev); + void pwm_hw_setPolarity(PwmDev dev, bool pol); + pwm_period_t pwm_hw_getPeriod(PwmDev dev); + +#else + #include <drv/pwm.h> + + typedef uint16_t pwm_hwreg_t; + + struct PwmChannelRegs; //fwd decl + + typedef struct PwmHardware + { + uint32_t pwm_pin; ///< PWM pin. + volatile struct PwmChannelRegs *base; + } PwmHardware; + + pwm_hwreg_t pwm_hw_getPeriod(Pwm *ctx); + void pwm_hw_setFrequency(struct Pwm *ctx, pwm_freq_t freq); + void pwm_hw_setDuty(Pwm *ctx, pwm_hwreg_t duty); + void pwm_hw_init(struct Pwm *ctx, unsigned ch); + +#endif #endif /* DRV_ADC_AT91_H */ diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/kdebug_avr.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/kdebug_avr.c index 8fa1a4b..e5718c9 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/kdebug_avr.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/kdebug_avr.c @@ -355,6 +355,7 @@ INLINE void kdbg_hw_init(void) #if CONFIG_KDEBUG_PORT == 0 UBRR0H = (uint8_t)(period>>8); UBRR0L = (uint8_t)period; + UCSR0A = 0; /* The Arduino Uno bootloader turns on U2X0 */ KDBG_UART0_BUS_INIT; #else #error Only CONFIG_KDEBUG_PORT 0 is supported for this cpu diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/ser_avr.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/ser_avr.c index 7f8cf93..ce44fd1 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/ser_avr.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/avr/drv/ser_avr.c @@ -146,6 +146,7 @@ * - Enable only the RX complete interrupt */ #define SER_UART0_BUS_TXINIT do { \ + UCSR0A = 0; /* The Arduino Uno bootloader turns on U2X0 */ \ UCSR0B = BV(BIT_RXCIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0); \ } while (0) #endif @@ -457,7 +458,20 @@ struct AvrSerial volatile bool sending; }; +static uint16_t uart_period(unsigned long bps) +{ + uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, bps) - 1; + + #ifdef _DEBUG + long skew = bps - (long)(period + 1) * (CPU_FREQ / 16); + /* 8N1 is reliable within 3% skew */ + if ((unsigned long)ABS(skew) > bps / (100 / 3)) + kprintf("Baudrate off by %ldbps\n", skew); + #endif + //DB(kprintf("uart_period(bps=%lu): period=%u\n", bps, period);) + return period; +} /* * Callbacks @@ -494,15 +508,12 @@ static void uart0_enabletxirq(struct SerialHardware *_hw) static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate) { - /* Compute baud-rate period */ - uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; + uint16_t period = uart_period(rate); #if !CPU_AVR_ATMEGA103 - UBRR0H = (period) >> 8; + UBRR0H = period >> 8; #endif - UBRR0L = (period); - - //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);) + UBRR0L = period; } static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity) @@ -547,13 +558,9 @@ static void uart1_enabletxirq(struct SerialHardware *_hw) static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate) { - /* Compute baud-rate period */ - uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; - - UBRR1H = (period) >> 8; - UBRR1L = (period); - - //DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);) + uint16_t period = uart_period(rate); + UBRR1H = period >> 8; + UBRR1L = period; } static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity) @@ -598,13 +605,9 @@ static void uart2_enabletxirq(struct SerialHardware *_hw) static void uart2_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate) { - /* Compute baud-rate period */ - uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; - - UBRR2H = (period) >> 8; - UBRR2L = (period); - - //DB(kprintf("uart2_setbaudrate(rate=%ld): period=%d\n", rate, period);) + uint16_t period = uart_period(rate); + UBRR2H = period >> 8; + UBRR2L = period; } static void uart2_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity) @@ -649,13 +652,9 @@ static void uart3_enabletxirq(struct SerialHardware *_hw) static void uart3_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate) { - /* Compute baud-rate period */ - uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; - - UBRR3H = (period) >> 8; - UBRR3L = (period); - - //DB(kprintf("uart3_setbaudrate(rate=%ld): period=%d\n", rate, period);) + uint16_t period = uart_period(rate); + UBRR3H = period >> 8; + UBRR3L = period; } static void uart3_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity) diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/adc_cm3.h b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/adc_cm3.h index b9987e4..168a5da 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/adc_cm3.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/adc_cm3.h @@ -42,6 +42,8 @@ #include "adc_lm3s.h" #elif CPU_CM3_STM32 #include "adc_stm32.h" +#elif CPU_CM3_SAM3X + #include "adc_sam3.h" /*#elif Add other ARM families here */ #else #error Unknown CPU diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/can_stm32.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/can_stm32.c index 8f7f194..494c68e 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/can_stm32.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/can_stm32.c @@ -33,6 +33,8 @@ * \brief CAN hardware-specific implementation * * \author Nicolas Dandrimont <Nic...@cr...> + * + * $WIZ$ */ #include "can_stm32.h" @@ -52,6 +54,7 @@ #include <cfg/log.h> #include <drv/can.h> +#include <drv/timer.h> #include <drv/clock_stm32.h> #include <drv/gpio_stm32.h> @@ -62,6 +65,16 @@ #include <drv/irq_cm3.h> +/** + * CAN Remapping values for STM32 + * + * $WIZ$ can_stm32_remaps = "CAN_STM32_PORTA", "CAN_STM32_PORTB", "CAN_STM32_PORTD" + * \{ + */ +#define CAN_STM32_PORTA 0 +#define CAN_STM32_PORTB 1 +#define CAN_STM32_PORTD 2 +/* \} */ static can_driver _cand1; can_driver *CAND1 = &_cand1; @@ -139,11 +152,33 @@ void can_hw_init(void) // Enable the clocks RCC->APB2ENR |= RCC_APB2_AFIO; + +#if CAN_STM32_REMAP == CAN_STM32_PORTA RCC->APB2ENR |= RCC_APB2_GPIOA; +#elif CAN_STM32_REMAP == CAN_STM32_PORTB + RCC->APB2ENR |= RCC_APB2_GPIOB; +#elif CAN_STM32_REMAP == CAN_STM32_PORTD + RCC->APB2ENR |= RCC_APB2_GPIOD; +#else + #error "CAN remapping not supported for stm32" +#endif // Set the pins to the right mode for CAN. - stm32_gpioPinConfig((struct stm32_gpio *)GPIOA_BASE, BV(11), GPIO_MODE_IN_FLOATING, GPIO_SPEED_10MHZ); +#if CAN_STM32_REMAP == CAN_STM32_PORTA + stm32_gpioPinConfig((struct stm32_gpio *)GPIOA_BASE, BV(11), GPIO_MODE_IPU, GPIO_SPEED_50MHZ); stm32_gpioPinConfig((struct stm32_gpio *)GPIOA_BASE, BV(12), GPIO_MODE_AF_PP, GPIO_SPEED_50MHZ); +#elif CAN_STM32_REMAP == CAN_STM32_PORTB + stm32_gpioRemap(GPIO_REMAP1_CAN1, GPIO_REMAP_ENABLE); + stm32_gpioPinConfig((struct stm32_gpio *)GPIOB_BASE, BV(8), GPIO_MODE_IPU, GPIO_SPEED_50MHZ); + stm32_gpioPinConfig((struct stm32_gpio *)GPIOB_BASE, BV(9), GPIO_MODE_AF_PP, GPIO_SPEED_50MHZ); +#elif CAN_STM32_REMAP == CAN_STM32_PORTD + stm32_gpioRemap(GPIO_REMAP2_CAN1, GPIO_REMAP_ENABLE); + stm32_gpioPinConfig((struct stm32_gpio *)GPIOD_BASE, BV(0), GPIO_MODE_IPU, GPIO_SPEED_50MHZ); + stm32_gpioPinConfig((struct stm32_gpio *)GPIOD_BASE, BV(1), GPIO_MODE_AF_PP, GPIO_SPEED_50MHZ); +#else + #error "CAN remapping not supported for stm32" +#endif + } void can_hw_start(can_driver *drv) { diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.c new file mode 100644 index 0000000..889a5c1 --- /dev/null +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.c @@ -0,0 +1,512 @@ +/** + * \file + * <!-- + * This file is part of BeRTOS. + * + * Bertos 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2010,2011 Develer S.r.l. (http://www.develer.com/) + * All Rights Reserved. + * --> + * + * \brief EMAC driver for AT91SAM family with Davicom 9161A phy. + * + * \author Daniele Basile <as...@de...> + * \author Andrea Righi <ar...@de...> + * \author Stefano Fedrigo <al...@de...> + */ + +#include "cfg/cfg_eth.h" + +#define LOG_LEVEL ETH_LOG_LEVEL +#define LOG_FORMAT ETH_LOG_FORMAT + +#include <cfg/log.h> + +#include <cfg/debug.h> +#include <cfg/log.h> +#include <cfg/macros.h> +#include <cfg/compiler.h> + +// TODO: unify includes +//#include <io/at91sam7.h> +//#include <io/arm.h> +//#include <io/include.h> +#include <io/sam3.h> +#include <drv/irq_cm3.h> + +#include <cpu/power.h> +#include <cpu/types.h> +#include <cpu/irq.h> + +#include <drv/timer.h> +#include <drv/eth.h> + +#include <mware/event.h> + +#include <string.h> + +#include "eth_sam3.h" + +#define EMAC_RX_INTS (BV(EMAC_RCOMP) | BV(EMAC_ROVR) | BV(EMAC_RXUBR)) +#define EMAC_TX_INTS (BV(EMAC_TCOMP) | BV(EMAC_TXUBR) | BV(EMAC_RLEX)) + +/* + * MAC address configuration (please change this in your project!). + * + * TODO: make this paramater user-configurable from the Wizard. + */ +const uint8_t mac_addr[] = { 0x00, 0x23, 0x54, 0x6a, 0x77, 0x55 }; + +/* Silent Doxygen bug... */ +#ifndef __doxygen__ +/* + * NOTE: this buffer should be declared as 'volatile' because it is read by the + * hardware. However, this is accessed only via memcpy() that should guarantee + * coherency when copying from/to buffers. + */ +static uint8_t tx_buf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] ALIGNED(8); +static volatile BufDescriptor tx_buf_tab[EMAC_TX_DESCRIPTORS] ALIGNED(8); + +/* + * NOTE: this buffer should be declared as 'volatile' because it is wrote by + * the hardware. However, this is accessed only via memcpy() that should + * guarantee coherency when copying from/to buffers. + */ +static uint8_t rx_buf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] ALIGNED(8); +static volatile BufDescriptor rx_buf_tab[EMAC_RX_DESCRIPTORS] ALIGNED(8); +#endif + +static int tx_buf_idx; +static int tx_buf_offset; +static int rx_buf_idx; + +static Event recv_wait, send_wait; + +static DECLARE_ISR(emac_irqHandler) +{ + /* Read interrupt status and disable interrupts. */ + uint32_t isr = EMAC_ISR; + + kprintf("irq: %x\n", isr); + + /* Receiver interrupt */ + if ((isr & EMAC_RX_INTS)) + { + kprintf("emac: rx %x\n", isr); + if (isr & BV(EMAC_RCOMP)) + event_do(&recv_wait); + EMAC_RSR = EMAC_RX_INTS; + } + /* Transmitter interrupt */ + if (isr & EMAC_TX_INTS) + { + if (isr & BV(EMAC_TCOMP)) + { + kprintf("emac: tcomp\n"); + event_do(&send_wait); + } + if (isr & BV(EMAC_RLEX)) + kprintf("emac: rlex\n"); + EMAC_TSR = EMAC_TX_INTS; + } + //AIC_EOICR = 0; +} + +/* + * \brief Read contents of PHY register. + * + * \param reg PHY register number. + * + * \return Contents of the specified register. + */ +static uint16_t phy_hw_read(reg8_t reg) +{ + // PHY read command. + EMAC_MAN = EMAC_SOF | EMAC_RW_READ | (NIC_PHY_ADDR << EMAC_PHYA_SHIFT) + | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA) | EMAC_CODE; + + // Wait until PHY logic completed. + while (!(EMAC_NSR & BV(EMAC_IDLE))) + cpu_relax(); + + // Get data from PHY maintenance register. + return (uint16_t)(EMAC_MAN & EMAC_DATA); +} + +/* + * \brief Write value to PHY register. + * + * \param reg PHY register number. + * \param val Value to write. + */ +static void phy_hw_write(reg8_t reg, uint16_t val) +{ + // PHY write command. + EMAC_MAN = EMAC_SOF | EMAC_RW_WRITE | (NIC_PHY_ADDR << EMAC_PHYA_SHIFT) + | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA) | EMAC_CODE | val; + + // Wait until PHY logic completed. + while (!(EMAC_NSR & BV(EMAC_IDLE))) + cpu_relax(); +} + +static int emac_reset(void) +{ + uint16_t phy_cr; + + // Enable devices + //PMC_PCER = BV(PIOA_ID); + //PMC_PCER = BV(PIOB_ID); + //PMC_PCER = BV(EMAC_ID); + // TOOD: Implement in sam7x + pmc_periphEnable(PIOA_ID); + pmc_periphEnable(PIOB_ID); + pmc_periphEnable(EMAC_ID); + + // Disable TESTMODE + PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT); +#if CPU_ARM_AT91 + // Disable RMII + PIOB_PUDR = BV(PHY_COL_RMII_BIT); + + // Disable PHY power down. + PIOB_PER = BV(PHY_PWRDN_BIT); + PIOB_OER = BV(PHY_PWRDN_BIT); + PIOB_CODR = BV(PHY_PWRDN_BIT); +#endif + + // Toggle external hardware reset pin. + RSTC_MR = RSTC_KEY | (1 << RSTC_ERSTL_SHIFT) | BV(RSTC_URSTEN); + RSTC_CR = RSTC_KEY | BV(RSTC_EXTRST); + + while ((RSTC_SR & BV(RSTC_NRSTL)) == 0) + cpu_relax(); + + // Configure MII ports. +#if CPU_ARM_AT91 + PIOB_ASR = PHY_MII_PINS; + PIOB_BSR = 0; + PIOB_PDR = PHY_MII_PINS; + // Enable receive and transmit clocks. + EMAC_USRIO = BV(EMAC_CLKEN); +#else + PIO_PERIPH_SEL(PIOB_BASE, PHY_MII_PINS, PIO_PERIPH_A); + PIOB_PDR = PHY_MII_PINS; + // Enable receive, transmit clocks and RMII mode. + EMAC_USRIO = BV(EMAC_CLKEN) | BV(EMAC_RMII); +#endif + + // Enable management port. + EMAC_NCR |= BV(EMAC_MPE); + EMAC_NCFGR |= EMAC_CLK_HCLK_32; + + // Set local MAC address. + EMAC_SA1L = (mac_addr[3] << 24) | (mac_addr[2] << 16) | + (mac_addr[1] << 8) | mac_addr[0]; + EMAC_SA1H = (mac_addr[5] << 8) | mac_addr[4]; + + // Wait for PHY ready + timer_delay(255); + + // Clear MII isolate. + phy_hw_read(NIC_PHY_BMCR); + phy_cr = phy_hw_read(NIC_PHY_BMCR); + + phy_cr &= ~NIC_PHY_BMCR_ISOLATE; + phy_hw_write(NIC_PHY_BMCR, phy_cr); + + phy_cr = phy_hw_read(NIC_PHY_BMCR); + + LOG_INFO("%s: PHY ID %#04x %#04x\n", + __func__, + phy_hw_read(NIC_PHY_ID1), phy_hw_read(NIC_PHY_ID2)); + + // Wait for auto negotiation completed. + phy_hw_read(NIC_PHY_BMSR); + for (;;) + { + if (phy_hw_read(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) + break; + cpu_relax(); + } + + // Disable management port. + EMAC_NCR &= ~BV(EMAC_MPE); + + return 0; +} + +static int emac_start(void) +{ + uint32_t addr; + int i; + + for (i = 0; i < EMAC_RX_DESCRIPTORS; i++) + { + addr = (uint32_t)(rx_buf + (i * EMAC_RX_BUFSIZ)); + rx_buf_tab[i].addr = addr & BUF_ADDRMASK; + } + rx_buf_tab[EMAC_RX_DESCRIPTORS - 1].addr |= RXBUF_WRAP; + + for (i = 0; i < EMAC_TX_DESCRIPTORS; i++) + { + addr = (uint32_t)(tx_buf + (i * EMAC_TX_BUFSIZ)); + tx_buf_tab[i].addr = addr & BUF_ADDRMASK; + tx_buf_tab[i].stat = TXS_USED; + } + tx_buf_tab[EMAC_TX_DESCRIPTORS - 1].stat = TXS_USED | TXS_WRAP; + + /* Tell the EMAC where to find the descriptors. */ + EMAC_RBQP = (uint32_t)rx_buf_tab; + EMAC_TBQP = (uint32_t)tx_buf_tab; + + /* Clear receiver status. */ + EMAC_RSR = BV(EMAC_OVR) | BV(EMAC_REC) | BV(EMAC_BNA); + + /* Copy all frames and discard FCS. */ + EMAC_NCFGR |= BV(EMAC_CAF) | BV(EMAC_DRFCS); + + /* Enable receiver, transmitter and statistics. */ + EMAC_NCR |= BV(EMAC_TE) | BV(EMAC_RE) | BV(EMAC_WESTAT); + + return 0; +} + +ssize_t eth_putFrame(const uint8_t *buf, size_t len) +{ + size_t wr_len; + + if (UNLIKELY(!len)) + return -1; + ASSERT(len <= sizeof(tx_buf)); + + /* Check if the transmit buffer is available */ + while (!(tx_buf_tab[tx_buf_idx].stat & TXS_USED)) + event_wait(&send_wait); + + /* Copy the data into the buffer and prepare descriptor */ + wr_len = MIN(len, (size_t)EMAC_TX_BUFSIZ - tx_buf_offset); + memcpy((uint8_t *)tx_buf_tab[tx_buf_idx].addr + tx_buf_offset, + buf, wr_len); + tx_buf_offset += wr_len; + + return wr_len; +} + +void eth_sendFrame(void) +{ + tx_buf_tab[tx_buf_idx].stat = (tx_buf_offset & TXS_LENGTH_FRAME) | + TXS_LAST_BUFF | + ((tx_buf_idx == EMAC_TX_DESCRIPTORS - 1) ? TXS_WRAP : 0); + EMAC_NCR |= BV(EMAC_TSTART); + + tx_buf_offset = 0; + if (++tx_buf_idx >= EMAC_TX_DESCRIPTORS) + tx_buf_idx = 0; +} + +ssize_t eth_send(const uint8_t *buf, size_t len) + { + if (UNLIKELY(!len)) + return -1; + + len = eth_putFrame(buf, len); + eth_sendFrame(); + + return len; +} + +static void eth_buf_realign(int idx) +{ + /* Empty buffer found. Realign. */ + do { + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + } while (idx != rx_buf_idx); +} + +static size_t __eth_getFrameLen(void) +{ + int idx, n = EMAC_RX_BUFFERS; + +skip: + /* Skip empty buffers */ + while ((n > 0) && !(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP)) + { + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + n--; + } + if (UNLIKELY(!n)) + { + LOG_INFO("no frame found\n"); + return 0; + } + /* Search the start of frame and cleanup fragments */ + while ((n > 0) && (rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP) && + !(rx_buf_tab[rx_buf_idx].stat & RXS_SOF)) + { + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_BUFFERS) + rx_buf_idx = 0; + n--; + } + if (UNLIKELY(!n)) + { + LOG_INFO("no SOF found\n"); + return 0; + } + /* Search end of frame to evaluate the total frame size */ + idx = rx_buf_idx; +restart: + while (n > 0) + { + if (UNLIKELY(!(rx_buf_tab[idx].addr & RXBUF_OWNERSHIP))) + { + /* Empty buffer found. Realign. */ + eth_buf_realign(idx); + goto skip; + } + if (rx_buf_tab[idx].stat & RXS_EOF) + return rx_buf_tab[idx].stat & RXS_LENGTH_FRAME; + if (UNLIKELY((idx != rx_buf_idx) && + (rx_buf_tab[idx].stat & RXS_SOF))) + { + /* Another start of frame found. Realign. */ + eth_buf_realign(idx); + goto restart; + } + if (++idx >= EMAC_RX_BUFFERS) + idx = 0; + n--; + } + LOG_INFO("no EOF found\n"); + return 0; +} + +size_t eth_getFrameLen(void) +{ + size_t len; + + /* Check if there is at least one available frame in the buffer */ + while (1) + { + len = __eth_getFrameLen(); + if (LIKELY(len)) + break; + /* Wait for RX interrupt */ + event_wait(&recv_wait); + } + return len; +} + +ssize_t eth_getFrame(uint8_t *buf, size_t len) +{ + uint8_t *addr; + size_t rd_len = 0; + + if (UNLIKELY(!len)) + return -1; + ASSERT(len <= sizeof(rx_buf)); + + /* Copy data from the RX buffer */ + addr = (uint8_t *)(rx_buf_tab[rx_buf_idx].addr & BUF_ADDRMASK); + if (addr + len > &rx_buf[countof(rx_buf)]) + { + size_t count = &rx_buf[countof(rx_buf)] - addr; + + memcpy(buf, addr, count); + memcpy(buf + count, rx_buf, len - count); + } + else + { + memcpy(buf, addr, len); + } + /* Update descriptors */ + while (rd_len < len) + { + if (len - rd_len >= EMAC_RX_BUFSIZ) + rd_len += EMAC_RX_BUFSIZ; + else + rd_len += len - rd_len; + if (UNLIKELY(!(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP))) + { + LOG_INFO("bad frame found\n"); + return 0; + } + rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP; + if (++rx_buf_idx >= EMAC_RX_DESCRIPTORS) + rx_buf_idx = 0; + } + + return rd_len; +} + +ssize_t eth_recv(uint8_t *buf, size_t len) +{ + if (UNLIKELY(!len)) + return -1; + len = MIN(len, eth_getFrameLen()); + return len ? eth_getFrame(buf, len) : 0; +} + +int eth_init() +{ + cpu_flags_t flags; + + emac_reset(); + emac_start(); + + event_initGeneric(&recv_wait); + event_initGeneric(&send_wait); + + // Register interrupt vector + IRQ_SAVE_DISABLE(flags); + + /* Disable all emac interrupts */ + EMAC_IDR = 0xFFFFFFFF; + +#if CPU_ARM_AT91 + // TODO: define sysirq_set... + /* Set the vector. */ + AIC_SVR(EMAC_ID) = emac_irqHandler; + /* Initialize to edge triggered with defined priority. */ + AIC_SMR(EMAC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED; + /* Clear pending interrupt */ + AIC_ICCR = BV(EMAC_ID); + /* Enable the system IRQ */ + AIC_IECR = BV(EMAC_ID); +#else + sysirq_setHandler(INT_EMAC, emac_irqHandler); +#endif + + /* Enable interrupts */ + EMAC_IER = EMAC_RX_INTS | EMAC_TX_INTS; + + IRQ_RESTORE(flags); + + return 0; +} diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.h b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.h new file mode 100644 index 0000000..f733df9 --- /dev/null +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/eth_sam3.h @@ -0,0 +1,208 @@ +/** + * \file + * <!-- + * This file is part of BeRTOS. + * + * Bertos 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2009,2010,2011 Develer S.r.l. (http://www.develer.com/) + * All Rights Reserved. + * --> + * + * \brief EMAC driver for AT91SAM family with Davicom 9161A phy, interface. + * + * \author Daniele Basile <as...@de...> + * \author Andrea Righi <ar...@de...> + * \author Stefano Fedrigo <al...@de...> + */ + +#ifndef ETH_SAM3_H +#define ETH_SAM3_H + +// Settings and definition for DAVICOM 9161A +// \{ +#define NIC_PHY_ADDR 31 + +//Registry definition +#define NIC_PHY_BMCR 0x00 // Basic mode control register. +#define NIC_PHY_BMCR_COLTEST 0x0080 // Collision test. +#define NIC_PHY_BMCR_FDUPLEX 0x0100 // Full duplex mode. +#define NIC_PHY_BMCR_ANEGSTART 0x0200 // Restart auto negotiation. +#define NIC_PHY_BMCR_ISOLATE 0x0400 // Isolate from MII. +#define NIC_PHY_BMCR_PWRDN 0x0800 // Power-down. +#define NIC_PHY_BMCR_ANEGENA 0x1000 // Enable auto negotiation. +#define NIC_PHY_BMCR_100MBPS 0x2000 // Select 100 Mbps. +#define NIC_PHY_BMCR_LOOPBACK 0x4000 // Enable loopback mode. +#define NIC_PHY_BMCR_RESET 0x8000 // Software reset. + +#define NIC_PHY_BMSR 0x01 // Basic mode status register. +#define NIC_PHY_BMSR_ANCOMPL 0x0020 // Auto negotiation complete. +#define NIC_PHY_BMSR_ANEGCAPABLE 0x0008 // Able to do auto-negotiation +#define NIC_PHY_BMSR_LINKSTAT 0x0004 // Link status. + +#define NIC_PHY_ID1 0x02 // PHY identifier register 1. +#define NIC_PHY_ID2 0x03 // PHY identifier register 2. +#define NIC_PHY_ANAR 0x04 // Auto negotiation advertisement register. +#define NIC_PHY_ANLPAR 0x05 // Auto negotiation link partner availability register. +#define NIC_PHY_ANER 0x06 // Auto negotiation expansion register. + +#if CPU_ARM_AT91 + +/* + * Pin definition for DAVICOM 9161A. + * See schematics for AT91SAM7X-EK evalution board. + */ +// All pins in port B +#define PHY_TXCLK_ISOLATE_BIT 0 +#define PHY_REFCLK_XT2_BIT 0 +#define PHY_TXEN_BIT 1 +#define PHY_TXD0_BIT 2 +#define PHY_TXD1_BIT 3 +#define PHY_CRS_AD4_BIT 4 +#define PHY_RXD0_AD0_BIT 5 +#define PHY_RXD1_AD1_BIT 6 +#define PHY_RXER_RXD4_RPTR_BIT 7 +#define PHY_MDC_BIT 8 +#define PHY_MDIO_BIT 9 +#define PHY_TXD2_BIT 10 +#define PHY_TXD3_BIT 11 +#define PHY_TXER_TXD4_BIT 12 +#define PHY_RXD2_AD2_BIT 13 +#define PHY_RXD3_AD3_BIT 14 +#define PHY_RXDV_TESTMODE_BIT 15 +#define PHY_COL_RMII_BIT 16 +#define PHY_RXCLK_10BTSER_BIT 17 +#define PHY_PWRDN_BIT 18 +#define PHY_MDINTR_BIT 26 + +#define PHY_MII_PINS \ + BV(PHY_REFCLK_XT2_BIT) \ + | BV(PHY_TXEN_BIT) \ + | BV(PHY_TXD0_BIT) \ + | BV(PHY_TXD1_BIT) \ + | BV(PHY_CRS_AD4_BIT) \ + | BV(PHY_RXD0_AD0_BIT) \ + | BV(PHY_RXD1_AD1_BIT) \ + | BV(PHY_RXER_RXD4_RPTR_BIT) \ + | BV(PHY_MDC_BIT) \ + | BV(PHY_MDIO_BIT) \ + | BV(PHY_TXD2_BIT) \ + | BV(PHY_TXD3_BIT) \ + | BV(PHY_TXER_TXD4_BIT) \ + | BV(PHY_RXD2_AD2_BIT) \ + | BV(PHY_RXD3_AD3_BIT) \ + | BV(PHY_RXDV_TESTMODE_BIT) \ + | BV(PHY_COL_RMII_BIT) \ + | BV(PHY_RXCLK_10BTSER_BIT) + +#else + +/* + * Pin definition for DAVICOM 9161A. + * See schematics for SAM3X-EK evalution board. + */ +// Port B +#define PHY_TXCLK_ISOLATE_BIT 0 +#define PHY_REFCLK_XT2_BIT 0 +#define PHY_TXEN_BIT 1 +#define PHY_TXD0_BIT 2 +#define PHY_TXD1_BIT 3 +#define PHY_RXDV_TESTMODE_BIT 4 +#define PHY_RXD0_AD0_BIT 5 +#define PHY_RXD1_AD1_BIT 6 +#define PHY_RXER_RXD4_RPTR_BIT 7 +#define PHY_MDC_BIT 8 +#define PHY_MDIO_BIT 9 +// Port A +#define PHY_MDINTR_BIT 5 + +#define PHY_MII_PINS \ + BV(PHY_REFCLK_XT2_BIT) \ + | BV(PHY_TXEN_BIT) \ + | BV(PHY_TXD0_BIT) \ + | BV(PHY_TXD1_BIT) \ + | BV(PHY_RXDV_TESTMODE_BIT) \ + | BV(PHY_RXD0_AD0_BIT) \ + | BV(PHY_RXD1_AD1_BIT) \ + | BV(PHY_RXER_RXD4_RPTR_BIT) \ + | BV(PHY_MDC_BIT) \ + | BV(PHY_MDIO_BIT) + +#endif /* CPU_ARM_AT91 */ +// \} + + +#define EMAC_TX_BUFSIZ 1518 //!!! Don't change this +#define EMAC_TX_BUFFERS 1 //!!! Don't change this +#define EMAC_TX_DESCRIPTORS EMAC_TX_BUFFERS + +#define EMAC_RX_BUFFERS 32 //!!! Don't change this +#define EMAC_RX_BUFSIZ 128 //!!! Don't change this +#define EMAC_RX_DESCRIPTORS EMAC_RX_BUFFERS + +// Flag to manage local tx buffer +#define TXS_USED 0x80000000 //Used buffer. +#define TXS_WRAP 0x40000000 //Last descriptor. +#define TXS_ERROR 0x20000000 //Retry limit exceeded. +#define TXS_UNDERRUN 0x10000000 //Transmit underrun. +#define TXS_NO_BUFFER 0x08000000 //Buffer exhausted. +#define TXS_NO_CRC 0x00010000 //CRC not appended. +#define TXS_LAST_BUFF 0x00008000 //Last buffer of frame. +#define TXS_LENGTH_FRAME 0x000007FF // Length of frame including FCS. + +// Flag to manage local rx buffer +#define RXBUF_OWNERSHIP 0x00000001 +#define RXBUF_WRAP 0x00000002 + +#define BUF_ADDRMASK 0xFFFFFFFC + +#define RXS_BROADCAST_ADDR 0x80000000 // Broadcast address detected. +#define RXS_MULTICAST_HASH 0x40000000 // Multicast hash match. +#define RXS_UNICAST_HASH 0x20000000 // Unicast hash match. +#define RXS_EXTERNAL_ADDR 0x10000000 // External address match. +#define RXS_SA1_ADDR 0x04000000 // Specific address register 1 match. +#define RXS_SA2_ADDR 0x02000000 // Specific address register 2 match. +#define RXS_SA3_ADDR 0x01000000 // Specific address register 3 match. +#define RXS_SA4_ADDR 0x00800000 // Specific address register 4 match. +#define RXS_TYPE_ID 0x00400000 // Type ID match. +#define RXS_VLAN_TAG 0x00200000 // VLAN tag detected. +#define RXS_PRIORITY_TAG 0x00100000 // Priority tag detected. +#define RXS_VLAN_PRIORITY 0x000E0000 // VLAN priority. +#define RXS_CFI_IND 0x00010000 // Concatenation format indicator. +#define RXS_EOF 0x00008000 // End of frame. +#define RXS_SOF 0x00004000 // Start of frame. +#define RXS_RBF_OFFSET 0x00003000 // Receive buffer offset mask. +#define RXS_LENGTH_FRAME 0x000007FF // Length of frame including FCS. + +#define EMAC_RSR_BITS (BV(EMAC_BNA) | BV(EMAC_REC) | BV(EMAC_OVR)) +#define EMAC_TSR_BITS (BV(EMAC_UBR) | BV(EMAC_COL) | BV(EMAC_RLES) | \ + BV(EMAC_BEX) | BV(EMAC_COMP) | BV(EMAC_UND)) + +typedef struct BufDescriptor +{ + volatile uint32_t addr; + volatile uint32_t stat; +} BufDescriptor; + +#endif /* ETH_SAM3_H */ diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/flash_stm32.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/flash_stm32.c index 816cdd5..d92e914 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/flash_stm32.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/flash_stm32.c @@ -67,6 +67,7 @@ static bool flash_wait(struct KBlock *blk) ticks_t start = timer_clock(); while (true) { + cpu_relax(); if (!(EMB_FLASH->SR & FLASH_FLAG_BSY)) break; @@ -90,8 +91,6 @@ static bool flash_wait(struct KBlock *blk) LOG_ERR("Timeout..\n"); return false; } - - cpu_relax(); } return true; diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/kdebug_stm32.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/kdebug_stm32.c index 646d37f..a60d19e 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/kdebug_stm32.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/kdebug_stm32.c @@ -77,10 +77,9 @@ INLINE void kdbg_hw_init(void) RCC->APB2ENR |= RCC_APB2_AFIO; /* Configure USART pins */ #if CONFIG_KDEBUG_PORT == 0 - RCC->APB2ENR |= RCC_APB2_GPIOB; + RCC->APB2ENR |= RCC_APB2_GPIOA; RCC->APB2ENR |= RCC_APB2_USART1; - stm32_gpioRemap(GPIO_REMAP_USART1, GPIO_REMAP_ENABLE); - stm32_gpioPinConfig((struct stm32_gpio *)GPIOB_BASE, GPIO_USART1_TX_PIN, + stm32_gpioPinConfig((struct stm32_gpio *)GPIOA_BASE, GPIO_USART1_TX_PIN, GPIO_MODE_AF_PP, GPIO_SPEED_50MHZ); #elif CONFIG_KDEBUG_PORT == 1 RCC->APB2ENR |= RCC_APB2_GPIOA; diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/usb_stm32.c b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/usb_stm32.c index 46069ff..393b3cc 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/usb_stm32.c +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/drv/usb_stm32.c @@ -1123,7 +1123,8 @@ static void usb_endpointRead_complete(int ep) rx_size = ep_cnfg[ep].size; } -ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size) +ssize_t usb_endpointReadTimeout(int ep, void *buffer, ssize_t size, + ticks_t timeout) { int ep_num = usb_ep_logical_to_hw(ep); ssize_t max_size = sizeof(ep_buffer[ep_num]); @@ -1158,7 +1159,11 @@ ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size) /* Blocking read */ __usb_ep_read(ep_num, ep_buffer[ep_num], size, usb_endpointRead_complete); - event_wait(&usb_event_done[ep_num >> 1]); + if (timeout < 0) + event_wait(&usb_event_done[ep_num >> 1]); + else + if (!event_waitTimeout(&usb_event_done[ep_num >> 1], timeout)) + return 0; memcpy(buffer, ep_buffer[ep_num], rx_size); return rx_size; @@ -1177,7 +1182,8 @@ static void usb_endpointWrite_complete(int ep) tx_size = ep_cnfg[ep].size; } -ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size) +ssize_t usb_endpointWriteTimeout(int ep, const void *buffer, ssize_t size, + ticks_t timeout) { int ep_num = usb_ep_logical_to_hw(ep); ssize_t max_size = sizeof(ep_buffer[ep_num]); @@ -1213,7 +1219,11 @@ ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size) memcpy(ep_buffer[ep_num], buffer, size); __usb_ep_write(ep_num, ep_buffer[ep_num], size, usb_endpointWrite_complete); - event_wait(&usb_event_done[ep_num >> 1]); + if (timeout < 0) + event_wait(&usb_event_done[ep_num >> 1]); + else + if (!event_waitTimeout(&usb_event_done[ep_num >> 1], timeout)) + return 0; return tx_size; } diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3.h b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3.h index ef5efa0..9437c61 100644 --- a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3.h +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3.h @@ -158,6 +158,7 @@ #include "sam3_sysctl.h" #include "sam3_pmc.h" #include "sam3_smc.h" +#include "sam3_sdramc.h" #include "sam3_ints.h" #include "sam3_pio.h" #include "sam3_nvic.h" @@ -166,6 +167,9 @@ #include "sam3_spi.h" #include "sam3_flash.h" #include "sam3_wdt.h" +#include "sam3_emac.h" +#include "sam3_rstc.h" +#include "sam3_adc.h" /** * U(S)ART I/O pins diff --git a/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3_adc.h b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3_adc.h new file mode 100644 index 0000000..2545f23 --- /dev/null +++ b/elec/boards/USB_CAN/Firmware/bertos/cpu/cortex-m3/io/sam3_adc.h @@ -0,0 +1,200 @@ +/** + * \file + * <!-- + * This file is part of BeRTOS. + * + * Bertos 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2011 Develer S.r.l. (http://www.develer.com/) + * + * --> + * + * \author Daniele Basile <as...@de...> + * + * SAM3 Analog to Digital Converter. + * + */ + + +#ifndef SAM3_ADC_H +#define SAM3_ADC_H + +/** ADC registers base. */ +#define ADC_BASE 0x400C0000 + +/** + * ADC control register + * \{ + */ +#define ADC_CR_OFF 0x00000000 ///< Control register offeset. +#define ADC_CR (*((reg32_t *)(ADC_BASE + ADC_CR_OFF))) ///< Control register address. +#define ADC_SWRST 0 ///< Software reset. +#define ADC_START 1 ///< Start conversion. +/* \} */ + +/** + * ADC mode register + * \{ + */ +#define ADC_MR_OFF 0x00000004 ///< Mode register offeset. +#define ADC_MR (*((reg32_t *)(ADC_BASE + ADC_MR_OFF))) ///< Mode register address. +#define ADC_TRGEN 0 ///< Trigger enable. + +#define ADC_TRGSEL_TIOA0 0x00000000 ///< TIOA output of the timer counter channel 0. +#define ADC_TRGSEL_TIOA1 0x00000002 ///< TIOA output of the timer counter channel 1. +#define ADC_TRGSEL_TIOA2 0x00000004 ///< TIOA output of the timer counter channel 2. +#define ADC_TRGSEL_PWM0 0x0000000A ///< PWM Event Line 0. +#define ADC_TRGSEL_PWM1 0x0000000C ///< PWM Event Line 1. + +#define ADC_LOWRES 4 ///< Resolution 0: 12-bit, 1: 10-bit. +#define ADC_SLEEP 5 ///< Sleep mode. + + +/** + * Prescaler rate selection. + * ADCClock = MCK / ((ADC_PRESCALER_VALUE + 1) * 2) + */ +#define ADC_PRESCALER_MASK 0x0000FF00 ///< Prescaler rate selection mask. +#define ADC_PRESCALER_SHIFT 8 ///< Prescale rate selection shift. + +/** + * Start up timer. + */ +#define ADC_STARTUP_MASK 0x000F0000 ///< Start up timer mask. +#define ADC_STARTUP_SHIFT 16 ///< Start up timer shift. + +#define ADC_SUT0 0 ///< 0 period of ADCClock. +#define ADC_SUT8 1 ///< 8 period of ADCClock. +#define ADC_SUT16 2 ///< 16 period of ADCClock. +#define ADC_SUT24 3 ///< 24 period of ADCClock. +#define ADC_SUT64 4 ///< 64 period of ADCClock. +#define ADC_SUT80 5 ///< 80 period of ADCClock. +#define ADC_SUT96 6 ///< 96 period of ADCClock. +#define ADC_S... [truncated message content] |