SAMD21如何使用TCC设置PWM?
SAMD21 how to set PWM using TCC?
我正在编程 SAMD21,我需要 PWM
当我选择带 F 功能的引脚时 TCC0 输出:
PA22 - TCC0/WO[4]
PA23 - TCC0/WO[5]
我成功配置了 TCC0 基本计数器:
// enable clock for TCC0 - disable clock masking
PM->APBCMASK.reg |= PM_APBCMASK_TCC0;
// set GCLK1 as source to the TCC0 counter
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN(1) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x1A);
while(!SYSCTRL->PCLKSR.bit.DFLLRDY);
// set counter
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV64; // setting prescaler
TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM | TCC_WAVE_POL0;
while (TCC0->SYNCBUSY.bit.WAVE);
// set TOP (PER) value of counter - frequency
TCC0->CTRLA.bit.RESOLUTION = 0;
TCC0->PER.reg = 48'000'000 / (100 * 64) - 1; // Fpwm = Fglk / (PRESC(PER+1)) --> PER = Fglk / (Fpwm * PRESC) - 1
while (TCC0->SYNCBUSY.bit.PER);
但问题是如何配置比较通道 - SAMD21 只有 4 个比较通道 (CC),但我想输出到 WO[4] 和 WO[5]。
如何将给定的比较通道连接到 WO[x] 引脚?
感谢回答
编辑:
我也将引脚配置为多路复用(不确定是否正确):
PORT->Group[0].PINCFG->reg |= (1 << PIN_PA22) | (1 << PIN_PA23);
PORT->Group[0].PMUX->bit.PMUXE = (0x5 << (PIN_PA22/2));
PORT->Group[0].PMUX->bit.PMUXO = (0x5 << (PIN_PA23/2 + 1));
注意:PORT->Group[0].PMUX
是一个数组!如果您执行 PMUX->bit
,它会衰减为指向第一个元素的指针,因此它可以编译,但它是错误的。您设置的是第一个元素,而不是您感兴趣的引脚 PIN_PA22/2
。
ASF 寄存器映射中的路由 PMUX
寄存器类型如下所示:
typedef union {
struct {
uint8_t PMUXE:4; /*!< bit: 0.. 3 Peripheral Multiplexing for Even-Numbered Pin */
uint8_t PMUXO:4; /*!< bit: 4.. 7 Peripheral Multiplexing for Odd-Numbered Pin */
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} PORT_PMUX_Type;
意味着您可以写入 8 位 reg
或 4 位 bit
半字节。你似乎做了后者。如果0x05
是手册中得到的"magic number",你应该把这个写到"even"和"odd"半字节。即:
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXE = (0x5 << 4);
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXO = (0x5 << 0);
或者,如果愿意,您也可以使用无意义的 ASF 英国媒体报道软件宏来隐藏 "scary" 按位逻辑:
PORT->Group[0].PMUX[PIN_PA22/2].reg = PORT_PMUX_PMUXE(0x5) | PORT_PMUX_PMUXO(0x5);
如果你没有把这些弄好,别针上根本就没有 activity。
有一个 PWM library 您可以 re-use 代码;它带有一个table(在“extras”下),带有定时器、输出引脚、输出通道、引脚多路复用器等
该库是(由我)为基于 SAMD21G 的 Arduinos 编写的,但是您需要的所有映射和代码都在那里,它可能会对您的工作有所帮助。
我正在编程 SAMD21,我需要 PWM 当我选择带 F 功能的引脚时 TCC0 输出: PA22 - TCC0/WO[4] PA23 - TCC0/WO[5]
我成功配置了 TCC0 基本计数器:
// enable clock for TCC0 - disable clock masking
PM->APBCMASK.reg |= PM_APBCMASK_TCC0;
// set GCLK1 as source to the TCC0 counter
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN(1) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x1A);
while(!SYSCTRL->PCLKSR.bit.DFLLRDY);
// set counter
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV64; // setting prescaler
TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM | TCC_WAVE_POL0;
while (TCC0->SYNCBUSY.bit.WAVE);
// set TOP (PER) value of counter - frequency
TCC0->CTRLA.bit.RESOLUTION = 0;
TCC0->PER.reg = 48'000'000 / (100 * 64) - 1; // Fpwm = Fglk / (PRESC(PER+1)) --> PER = Fglk / (Fpwm * PRESC) - 1
while (TCC0->SYNCBUSY.bit.PER);
但问题是如何配置比较通道 - SAMD21 只有 4 个比较通道 (CC),但我想输出到 WO[4] 和 WO[5]。
如何将给定的比较通道连接到 WO[x] 引脚?
感谢回答
编辑:
我也将引脚配置为多路复用(不确定是否正确):
PORT->Group[0].PINCFG->reg |= (1 << PIN_PA22) | (1 << PIN_PA23);
PORT->Group[0].PMUX->bit.PMUXE = (0x5 << (PIN_PA22/2));
PORT->Group[0].PMUX->bit.PMUXO = (0x5 << (PIN_PA23/2 + 1));
注意:PORT->Group[0].PMUX
是一个数组!如果您执行 PMUX->bit
,它会衰减为指向第一个元素的指针,因此它可以编译,但它是错误的。您设置的是第一个元素,而不是您感兴趣的引脚 PIN_PA22/2
。
ASF 寄存器映射中的路由 PMUX
寄存器类型如下所示:
typedef union {
struct {
uint8_t PMUXE:4; /*!< bit: 0.. 3 Peripheral Multiplexing for Even-Numbered Pin */
uint8_t PMUXO:4; /*!< bit: 4.. 7 Peripheral Multiplexing for Odd-Numbered Pin */
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} PORT_PMUX_Type;
意味着您可以写入 8 位 reg
或 4 位 bit
半字节。你似乎做了后者。如果0x05
是手册中得到的"magic number",你应该把这个写到"even"和"odd"半字节。即:
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXE = (0x5 << 4);
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXO = (0x5 << 0);
或者,如果愿意,您也可以使用无意义的 ASF 英国媒体报道软件宏来隐藏 "scary" 按位逻辑:
PORT->Group[0].PMUX[PIN_PA22/2].reg = PORT_PMUX_PMUXE(0x5) | PORT_PMUX_PMUXO(0x5);
如果你没有把这些弄好,别针上根本就没有 activity。
有一个 PWM library 您可以 re-use 代码;它带有一个table(在“extras”下),带有定时器、输出引脚、输出通道、引脚多路复用器等
该库是(由我)为基于 SAMD21G 的 Arduinos 编写的,但是您需要的所有映射和代码都在那里,它可能会对您的工作有所帮助。