⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwm.c

📁 实时嵌入式操作系统内部关于定时器的应用
💻 C
字号:
/*
 * pwm.c
 *
 * Copyright (C) STMicroelectronics Limited 2004. All rights reserved.
 *
 * In-built timer management for ST20-C1.
 */

#include <c1timer.h>
#include <interrup.h>
#include <osassert.h>
#include <ostime.h>
#include <task.h>

#include "pwm.h"

#ifdef C1_CORE

static int limit (int min, int val, int max)
{
	return val < min ? min :
	       val > max ? max :
	                   val;
}

static void *pwm_base_address;
static int pwm_raised, pwm_number;

static void pwm_raise(void)
{
	pwm_raised = 1;
	interrupt_raise_number(pwm_number);
}

#define PWM3 ((pwm3_t *) pwm_base_address)
static int  pwm3_read(void)     { return PWM3->CaptureCount; }
static void pwm3_set(int value) { PWM3->CompareVal0 = value; }
static void pwm3_enable(void)   { PWM3->IntEnable.CompareInt0 = 1; }
static void pwm3_disable(void)  { PWM3->IntEnable.CompareInt0 = 0; }
static timer_api_t pwm3_api = { pwm3_read, pwm3_set, pwm3_enable, pwm3_disable, pwm_raise };

static void pwm3_interrupt(pwm3_t *pwm3)
{
	while ((pwm3->IntStatus.CompareInt0 && pwm3->IntEnable.CompareInt0) || pwm_raised) {
		pwm_raised = 0;
		pwm3->IntAck.CompareInt0 = 1;
		timer_interrupt();
	}
}

static void pwm3_init(pwm3_t *pwm3, int freq)
{
	/* timeslice tick is hardwired. no config required. */

	/* calculate the system clock frequency (see pwm4_init for details) and enable */
	pwm3->Control.CaptureClkValue = limit(0, (freq*1000 / 15625) - 1, 31);
	time_ticks_per_sec_set((freq * 1000) / (pwm3->Control.CaptureClkValue + 1));
	pwm3->Control.CaptureEnable = 1;
   
	/* set up capture counter hardware */
	pwm3->CaptureCount = 0;
	pwm3->IntEnable.CompareInt0 = 0;
	pwm3->IntAck.CompareInt0 = ~0;
}

#define PWM4 ((pwm4_t *) pwm_base_address)
static int pwm4_read(void)      { return PWM4->CaptureCount; }
static void pwm4_set(int value) { PWM4->CompareVal0 = value; }
static void pwm4_enable(void)   { PWM4->IntEnable.CompareInt0 = 1; }
static void pwm4_disable(void)  { PWM4->IntEnable.CompareInt0 = 0; }
static timer_api_t pwm4_api = { pwm4_read, pwm4_set, pwm4_enable, pwm4_disable, pwm_raise };

static void pwm4_interrupt(pwm4_t *pwm4)
{
	while ((pwm4->IntStatus.CompareInt0 && pwm4->IntEnable.CompareInt0) || pwm_raised) {
		pwm_raised = 0;
		pwm4->IntAck.CompareInt0 = 1;
		timer_interrupt();
	}
}

static void pwm4_init(pwm4_t *pwm4, int freq)
{
	/* calculate and enable the C1 timeslice tick (freq is in khz)
	 *
	 * based on: target_khz * c1_slice_divide = freq / (pwm_divide * (prescale + 1)
         *
	 * where:         target_khz = 0.5 (2ms timeslice)
	 *           c1_slice_divide = 64
	 *                pwm_divide = 256
	 *
	 * thus:     0.5 * 64 = freq / 256 * (prescale+1)
	 * or:       prescale = (freq / (256 * 0.5 * 64)) - 1
	 *                    = (freq / 8192) - 1
	 *
	 */
	pwm4->Control.PWMClkValue = limit(0, (freq / 8192) - 1, 15);
	pwm4->Control.PWMEnable = 1;

	/* calculate the system clock frequency (freq is in khz) and enable
	 *
	 * based on: target_khz = freq / (prescale + 1)
	 *
	 * where:    target_khz = 15.625
         *
	 * thus:       15.625 = freq / (prescale + 1)
	 * or:	     prescale = (freq / 15.625) - 1
	 *
	 * note: since we perform the calculation as integers then we will
	 * overflow if freq is greater than 2GHz.
	 */
	pwm4->Control.CaptureClkValue = limit(0, (freq*1000 / 15625) - 1, 31);
	time_ticks_per_sec_set((freq * 1000) / (pwm4->Control.CaptureClkValue + 1));
	pwm4->Control.CaptureEnable = 1;

	/* set up capture counter hardware */
	pwm4->CaptureCount = 0;
	pwm4->IntEnable.CompareInt0 = 0;
	pwm4->IntAck.CompareInt0 = ~0;
}


int timer_init_pwm(void *base, int number, int level, int freq, 
                         timer_init_pwm_flags_t flags)
{
	void (*interrupt)();
	void (*init)();
	timer_api_t *api;

	int err;

	FATAL_ERROR_IF_NOT_TASK();
	FATAL_ERROR_IF_NULL(base);
	FATAL_ERROR_IF(freq > 2000000, "at frequencies over 2GHz internal "
	                               "calculations will overflow");
	FATAL_ERROR_IF(pwm_base_address, "timer_init_pwm() can only be called once");

	/* switch between PWM3 and PWM4 */
	if (timer_init_pwm_flags_pwm3 & flags) {
		interrupt = pwm3_interrupt;
		init = pwm3_init;
		api = &pwm3_api;
	} else {
		interrupt = pwm4_interrupt;
		init = pwm4_init;
		api = &pwm4_api;
	}

	err = interrupt_install(number, level, interrupt, base);
	if (0 != err) {
		return err;
	}

	pwm_base_address = base;
	pwm_number = number;
	
	init(base, freq);
	timer_initialize(api);

	return 0;
}

#endif /* C1_CORE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -