Project

General

Profile

Download (4.33 KB) Statistics
| Branch: | Tag: | Revision:
1 ada3d4fa (no author)
/* AT91SAM7 PWM routines for OpenPCD / OpenPICC
2
 * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
3
 *
4 32985a29 laforge
 *  This program is free software; you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by 
6
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  (at your option) any later version.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program; if not, write to the Free Software
16
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 *
18 ada3d4fa (no author)
 */
19
20
#include <lib_AT91SAM7.h>
21
#include <AT91SAM7.h>
22
#include <sys/types.h>
23
#include <errno.h>
24 81416e6a (no author)
#include <openpcd.h>
25 520784c7 (no author)
#include <os/usb_handler.h>
26
#include <os/pcd_enumerate.h>
27
#include <os/req_ctx.h>
28
#include <os/dbgu.h>
29
#include "../openpcd.h"
30 ada3d4fa (no author)
31
#define Hz
32
#define	kHz	*1000 Hz
33
#define MHz	*1000 kHz
34
#define MCLK	(48 MHz)
35
36 c604e0c2 (no author)
#if 1
37
#define DEBUGPWM DEBUGPCRF
38
#else
39
#define DEBUGPWM(x, args...)
40
#endif
41
42
static AT91PS_PWMC pwm = AT91C_BASE_PWMC;
43
44 ada3d4fa (no author)
/* find highest bit set. returns bit (32..1) or 0 in case no bit set  */
45 373c172a Harald Welte
static int fhs(uint32_t val)
46 ada3d4fa (no author)
{
47
	int i;
48
49
	for (i = 32; i > 0; i--) {
50
		if (val & (1 << (i-1)))
51
			return i;
52
	}
53
54
	return 0;
55
}
56
57
/* set frequency of PWM signal to freq */
58 373c172a Harald Welte
int pwm_freq_set(int channel, uint32_t freq)
59 ada3d4fa (no author)
{
60
	/* in order to get maximum resolution, the pre-scaler must be set to
61
	 * something like freq << 16.  However, the mimimum pre-scaled frequency
62
	 * we can get is MCLK (48MHz), the minimum is MCLK/(1024*255) =
63
	 * 48MHz/261120 = 183Hz */
64 373c172a Harald Welte
	uint32_t overall_div;
65
	uint32_t presc_total;
66
	uint8_t cpre = 0;
67
	uint16_t cprd;
68 ada3d4fa (no author)
69
	if (freq > MCLK)
70
		return -ERANGE;
71
	
72
	overall_div = MCLK / freq;
73 c604e0c2 (no author)
	DEBUGPCRF("mclk=%u, freq=%u, overall_div=%u", MCLK, freq, overall_div);
74 ada3d4fa (no author)
75 c604e0c2 (no author)
	if (overall_div > 0x7fff) {
76 ada3d4fa (no author)
		/* divisor is larger than half the maximum CPRD register, we
77
		 * have to configure prescalers */
78
		presc_total = overall_div >> 15;
79
80
		/* find highest 2^n fitting in prescaler (highest bit set) */
81
		cpre = fhs(presc_total);
82
		if (cpre > 0) {
83
			/* subtract one, because of fhs semantics */
84
			cpre--;
85
		}
86
		cprd = overall_div / (1 << cpre);
87
	} else
88
		cprd = overall_div;
89
	
90 c604e0c2 (no author)
	DEBUGPCRF("cpre=%u, cprd=%u", cpre, cprd);
91
	AT91F_PWMC_CfgChannel(AT91C_BASE_PWMC, channel, 
92
			      cpre|AT91C_PWMC_CPOL, cprd, 1);
93 ada3d4fa (no author)
94
	return 0;
95
}
96
97
void pwm_start(int channel)
98
{
99
	AT91F_PWMC_StartChannel(AT91C_BASE_PWMC, (1 << channel));
100
}
101
102
void pwm_stop(int channel)
103
{
104
	AT91F_PWMC_StopChannel(AT91C_BASE_PWMC, (1 << channel));
105
}
106
107 373c172a Harald Welte
void pwm_duty_set_percent(int channel, uint16_t duty)
108 ada3d4fa (no author)
{
109 373c172a Harald Welte
	uint32_t tmp = pwm->PWMC_CH[channel].PWMC_CPRDR & 0xffff;
110 c604e0c2 (no author)
	
111
	tmp = tmp << 16;	/* extend value by 2^16 */
112
	tmp = tmp / 100;	/* tmp = 1 % of extended cprd */
113
	tmp = duty * tmp;	/* tmp = 'duty' % of extended cprd */
114
	tmp = tmp >> 16;	/* un-extend tmp (divide by 2^16) */
115
116
	DEBUGPWM("Writing %u to Update register\n", tmp);
117
	AT91F_PWMC_UpdateChannel(AT91C_BASE_PWMC, channel, tmp);
118 ada3d4fa (no author)
}
119
120 81416e6a (no author)
static int pwm_usb_in(struct req_ctx *rctx)
121
{
122 514b0f72 laforge
	struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
123 373c172a Harald Welte
	uint32_t *freq;
124 81416e6a (no author)
125
	switch (poh->cmd) {
126
	case OPENPCD_CMD_PWM_ENABLE:
127
		if (poh->val)
128
			pwm_start(0);
129
		else
130
			pwm_stop(0);
131
		break;
132
	case OPENPCD_CMD_PWM_DUTY_SET:
133
		pwm_duty_set_percent(0, poh->val);
134
		break;
135
	case OPENPCD_CMD_PWM_DUTY_GET:
136
		goto respond;
137
		break;
138
	case OPENPCD_CMD_PWM_FREQ_SET:
139 514b0f72 laforge
		if (rctx->tot_len < sizeof(*poh)+4)
140 81416e6a (no author)
			break;
141 373c172a Harald Welte
		freq = (uint32_t *) ((unsigned char *) poh) + sizeof(*poh);
142 81416e6a (no author)
		pwm_freq_set(0, *freq);
143
		break;
144
	case OPENPCD_CMD_PWM_FREQ_GET:
145
		goto respond;
146
		break;
147
	default:
148
		break;
149
	}
150
151
	req_ctx_put(rctx);
152
	return 0;
153
respond:
154
	req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
155 514b0f72 laforge
	udp_refill_ep(2);
156 81416e6a (no author)
	return 1;
157
}
158
159 ada3d4fa (no author)
void pwm_init(void)
160
{
161 7822203b (no author)
	/* IMPORTANT: Disable PA17 (SSC TD) output */
162
	AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17);
163
164 bc7d72bf (no author)
	/* Set PA23 to Peripheral A (PWM0) */
165
	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, OPENPCD_PIO_MFIN_PWM);
166 ada3d4fa (no author)
167
	/* Enable Clock for PWM controller */
168
	AT91F_PWMC_CfgPMC();
169 81416e6a (no author)
170
	usb_hdlr_register(&pwm_usb_in, OPENPCD_CMD_CLS_PWM);
171 ada3d4fa (no author)
}
172
173
void pwm_fini(void)
174
{
175 81416e6a (no author)
	usb_hdlr_unregister(OPENPCD_CMD_CLS_PWM);
176 ada3d4fa (no author)
	AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, (1 << AT91C_ID_PWMC));
177
}
Add picture from clipboard (Maximum size: 48.8 MB)