diff options
author | (no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-08-03 10:00:21 +0000 |
---|---|---|
committer | (no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-08-03 10:00:21 +0000 |
commit | ada3d4fa86e6f178c8281f1cf7a5c55f8961accb (patch) | |
tree | def3f0c4749c4018b436ec66601cb11ff620ab08 | |
parent | 1bc8544204ae4a75ed8b4c76cee9fa3bd9d505d6 (diff) |
add code for PWM controller
git-svn-id: https://svn.openpcd.org:2342/trunk@71 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
-rw-r--r-- | openpcd/firmware/Makefile | 2 | ||||
-rw-r--r-- | openpcd/firmware/src/pwm.c | 94 | ||||
-rw-r--r-- | openpcd/firmware/src/pwm.h | 11 |
3 files changed, 106 insertions, 1 deletions
diff --git a/openpcd/firmware/Makefile b/openpcd/firmware/Makefile index c9c793e..247dcd5 100644 --- a/openpcd/firmware/Makefile +++ b/openpcd/firmware/Makefile @@ -74,7 +74,7 @@ SRC = # use file-extension c for "c-only"-files SRCARM = lib/lib_AT91SAM7.c src/pcd_enumerate.c src/fifo.c src/dbgu.c \ src/led.c src/rc632.c src/rc632_highlevel.c src/req_ctx.c \ - src/trigger.c src/main.c src/syscalls.c \ + src/trigger.c src/main.c src/syscalls.c src/pwm.c \ src/$(TARGET).c src/start/Cstartup_SAM7.c SRCARM += src/rfid_layer2_iso14443a.c diff --git a/openpcd/firmware/src/pwm.c b/openpcd/firmware/src/pwm.c new file mode 100644 index 0000000..90653f9 --- /dev/null +++ b/openpcd/firmware/src/pwm.c @@ -0,0 +1,94 @@ +/* AT91SAM7 PWM routines for OpenPCD / OpenPICC + * + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + */ + +#include <lib_AT91SAM7.h> +#include <AT91SAM7.h> +#include <sys/types.h> +#include <errno.h> + +#define Hz +#define kHz *1000 Hz +#define MHz *1000 kHz +#define MCLK (48 MHz) + +/* find highest bit set. returns bit (32..1) or 0 in case no bit set */ +static int fhs(u_int32_t val) +{ + int i; + + for (i = 32; i > 0; i--) { + if (val & (1 << (i-1))) + return i; + } + + return 0; +} + +/* set frequency of PWM signal to freq */ +int pwm_freq_set(int channel, u_int32_t freq) +{ + /* in order to get maximum resolution, the pre-scaler must be set to + * something like freq << 16. However, the mimimum pre-scaled frequency + * we can get is MCLK (48MHz), the minimum is MCLK/(1024*255) = + * 48MHz/261120 = 183Hz */ + u_int32_t overall_div; + u_int32_t presc_total; + u_int32_t cpre = 0; + u_int8_t cprd; + + if (freq > MCLK) + return -ERANGE; + + overall_div = MCLK / freq; + + if (overall_div > 0x7ffff) { + /* divisor is larger than half the maximum CPRD register, we + * have to configure prescalers */ + presc_total = overall_div >> 15; + + /* find highest 2^n fitting in prescaler (highest bit set) */ + cpre = fhs(presc_total); + if (cpre > 0) { + /* subtract one, because of fhs semantics */ + cpre--; + } + cprd = overall_div / (1 << cpre); + } else + cprd = overall_div; + + AT91F_PWMC_CfgChannel(AT91C_BASE_PWMC, channel, cpre, 0, cprd); + + return 0; +} + +void pwm_start(int channel) +{ + AT91F_PWMC_StartChannel(AT91C_BASE_PWMC, (1 << channel)); +} + +void pwm_stop(int channel) +{ + AT91F_PWMC_StopChannel(AT91C_BASE_PWMC, (1 << channel)); +} + +void pwm_duty(int channel, u_int16_t duty) +{ + AT91F_PWMC_UpdateChannel(AT91C_BASE_PWMC, channel, duty); +} + +void pwm_init(void) +{ + /* Set PA23 ti Peripheral B (PWM0) */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA23_PWM0); + + /* Enable Clock for PWM controller */ + AT91F_PWMC_CfgPMC(); +} + +void pwm_fini(void) +{ + AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, (1 << AT91C_ID_PWMC)); +} diff --git a/openpcd/firmware/src/pwm.h b/openpcd/firmware/src/pwm.h new file mode 100644 index 0000000..c41d74a --- /dev/null +++ b/openpcd/firmware/src/pwm.h @@ -0,0 +1,11 @@ +#ifndef _PWM_H +#define _PWM_H + +extern void pwm_freq_set(int channel, u_int32_t freq); +extern void pwm_start(int channel); +extern void pwm_stop(int channel); +extern void pwm_duty(int channel, u_int16_t duty); +extern void pwm_init(void); +extern void pwm_fini(void); + +#endif |