Сталкивался ли кто нибудь с такой проблемой, что при формировании ШИM-сигнала при помощи модуля PWM в сигнале возникают периоды когда выход остается в высоком уровне ?
Нажмите для просмотра прикрепленного файла
Код для работы с модулем PWM у меня такой:
CODE
/*
* ch3_8_hal.c
*
* Created on: 10.03.2012
* Author: Илья
*/
#include "LPC17xx.h"
#define MR0_INT (1 << 0)
#define MR1_INT (1 << 1)
#define MR2_INT (1 << 2)
#define MR3_INT (1 << 3)
#define MR4_INT (1 << 8)
#define MR5_INT (1 << 9)
#define MR6_INT (1 << 10)
#define TCR_CNT_EN 0x00000001
#define TCR_RESET 0x00000002
#define TCR_PWM_EN 0x00000008
#define PWMMR0I (1 << 0)
#define PWMMR0R (1 << 1)
#define PWMMR0S (1 << 2)
#define PWMMR1I (1 << 3)
#define PWMMR1R (1 << 4)
#define PWMMR1S (1 << 5)
#define PWMMR2I (1 << 6)
#define PWMMR2R (1 << 7)
#define PWMMR2S (1 << 8)
#define PWMMR3I (1 << 9)
#define PWMMR3R (1 << 10)
#define PWMMR3S (1 << 11)
#define PWMMR4I (1 << 12)
#define PWMMR4R (1 << 13)
#define PWMMR4S (1 << 14)
#define PWMMR5I (1 << 15)
#define PWMMR5R (1 << 16)
#define PWMMR5S (1 << 17)
#define PWMMR6I (1 << 18)
#define PWMMR6R (1 << 19)
#define PWMMR6S (1 << 20)
#define PWMSEL2 (1 << 2)
#define PWMSEL3 (1 << 3)
#define PWMSEL4 (1 << 4)
#define PWMSEL5 (1 << 5)
#define PWMSEL6 (1 << 6)
#define PWMENA1 (1 << 9)
#define PWMENA2 (1 << 10)
#define PWMENA3 (1 << 11)
#define PWMENA4 (1 << 12)
#define PWMENA5 (1 << 13)
#define PWMENA6 (1 << 14)
#define LER0_EN (1 << 0)
#define LER1_EN (1 << 1)
#define LER2_EN (1 << 2)
#define LER3_EN (1 << 3)
#define LER4_EN (1 << 4)
#define LER5_EN (1 << 5)
#define LER6_EN (1 << 6)
#define ACTIVE_TAKT_1_CH3 2
#define ACTIVE_TAKT_2_CH3 12
#define ACTIVE_TAKT_1_CH4 2
#define ACTIVE_TAKT_2_CH4 12
#define ACTIVE_TAKT_1_CH5 3
#define ACTIVE_TAKT_2_CH5 11
#define ACTIVE_TAKT_1_CH6 3
#define ACTIVE_TAKT_2_CH6 11
#define ACTIVE_TAKT_1_CH7 4
#define ACTIVE_TAKT_2_CH7 12
#define ACTIVE_TAKT_1_CH8 4
#define ACTIVE_TAKT_2_CH8 12
static uint_fast8_t current_takt;
//-----------------------------------------------------------------------------
static void pwm_ch3_8_irq_hw (void)
{
volatile uint32_t regVal;
volatile uint32_t load_value = 0ul;
//__disable_fault_irq();
//__disable_irq();
regVal = LPC_PWM1->IR;
LPC_PWM1->IR = regVal; /* clear interrupt flag on match 0 */
if( regVal & MR0_INT )
{
if(LPC_PWM1->MR1)
{
if(
current_takt == ACTIVE_TAKT_1_CH3 ||
current_takt == ACTIVE_TAKT_2_CH3
)
{
load_value |= 0x00008000;
}
}
if(LPC_PWM1->MR2)
{
if(
current_takt == ACTIVE_TAKT_1_CH4 ||
current_takt == ACTIVE_TAKT_2_CH4
)
{
load_value |= 0x00010000;
}
}
if(LPC_PWM1->MR3)
{
if(
current_takt == ACTIVE_TAKT_1_CH5 ||
current_takt == ACTIVE_TAKT_2_CH5
)
{
load_value |= 0x00020000;
}
}
if(LPC_PWM1->MR4)
{
if(
current_takt == ACTIVE_TAKT_1_CH6 ||
current_takt == ACTIVE_TAKT_2_CH6
)
{
load_value |= 0x00040000;
}
}
if(LPC_PWM1->MR5)
{
if(
current_takt == ACTIVE_TAKT_1_CH7 ||
current_takt == ACTIVE_TAKT_2_CH7
)
{
load_value |= 0x40000000;
}
}
LPC_GPIO0->FIOSET = load_value; /* swich on */
if(LPC_PWM1->MR6)
{
if(
current_takt == ACTIVE_TAKT_1_CH8 ||
current_takt == ACTIVE_TAKT_2_CH8
)
{
LPC_GPIO1->FIOSET = 0x00008000;
}
}
//return;
}
load_value = 0ul; // Обнуляю переменную перед тем как использовать ее еще раз
if( regVal & MR1_INT )
load_value |= 0x00008000;
if( regVal & MR2_INT )
load_value |= 0x00010000;
if( regVal & MR3_INT )
load_value |= 0x00020000;
if( regVal & MR4_INT )
load_value |= 0x00040000;
if( regVal & MR5_INT )
load_value |= 0x40000000;
LPC_GPIO0->FIOCLR = load_value;
if( regVal & MR6_INT )
LPC_GPIO1->FIOCLR = 0x00008000;
// __enable_fault_irq();
// __enable_irq();
}
//-----------------------------------------------------------------------------
static void ch3_8_init_hw(void)
{
// Out_3, Out_4
LPC_PINCON->PINSEL0 &= 0x3FFFFFFF; // P0.15 as GPIO port
LPC_PINCON->PINSEL1 &= 0xCFFFFFC0; // Настрою P0.16...P0.18, P0.30 как GPIO
// и обнулю выходы
LPC_PINCON->PINSEL2 &= 0x3FFFFFFF; // P1.15 as GPIO port
LPC_PINCON->PINMODE0 &= 0x3FFFFFFF; // not pull-... mode
LPC_PINCON->PINMODE0 |= 0x80000000;
LPC_PINCON->PINMODE1 &= 0xCFFFFFC0; // not pull-... mode
LPC_PINCON->PINMODE1 |= 0x2F00002A;
LPC_PINCON->PINMODE2 &= 0x3FFFFFFF; // not pull-... mode
LPC_PINCON->PINMODE2 |= 0x80000000;
LPC_PINCON->PINMODE_OD0 &= 0xBFF87FFF;
LPC_PINCON->PINMODE_OD1 &= 0xFFFF7FFF;
LPC_GPIO0->FIODIR |= 0x40078000;
LPC_GPIO0->FIOCLR = 0x40078000;
LPC_GPIO1->FIODIR |= 0x00008000;
LPC_GPIO1->FIOCLR = 0x00008000;
// Следующие две строчки должны быть одикаковы для всех каналов PWM
LPC_PWM1->TCR = TCR_CNT_EN | TCR_RESET; /* Counter enable, Counter Reset*/
LPC_PWM1->PR = 0ul; /* count frequency:Fpclk */
LPC_PWM1->MR0 = 0ul;
LPC_PWM1->MR1 = 0ul;
LPC_PWM1->MR2 = 0ul;
LPC_PWM1->MR3 = 0ul;
LPC_PWM1->MR4 = 0ul;
LPC_PWM1->MR5 = 0ul;
LPC_PWM1->MR6 = 0ul;
LPC_PWM1->PCR = 0ul;
LPC_PWM1->MCR = PWMMR0R | PWMMR0I | PWMMR1I | PWMMR2I |
PWMMR3I | PWMMR4I | PWMMR5I | PWMMR6I;
NVIC_SetPriority(PWM1_IRQn,0);
NVIC_EnableIRQ(PWM1_IRQn);
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_start_hw(void)
{
/* All single edge, all enable */
// LPC_PWM1->TCR &= ~(TCR_RESET);
// LPC_PWM1->TCR |= TCR_PWM_EN;
LPC_PWM1->TCR = 0x00000009; /* counter enable, ResetdisablePWM enable */
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_stop_hw(void)
{
LPC_PWM1->MR0 = 0ul; /* set PWM cycle */
/* set PWM offsets */
LPC_PWM1->MR1 = 0ul;
LPC_PWM1->MR2 = 0ul;
LPC_PWM1->MR3 = 0ul;
LPC_PWM1->MR4 = 0ul;
LPC_PWM1->MR5 = 0ul;
LPC_PWM1->MR6 = 0ul;
LPC_PWM1->LER |= 0x0000007F;
LPC_PWM1->TCR |= TCR_RESET; /* Counter Reset */
LPC_GPIO0->FIOCLR = 0x40078000;
LPC_GPIO1->FIOCLR = 0x00008000;
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_set_freq_offset_hw(uint32_t cycle, uint_fast8_t takt, uint32_t* p_offset_arr)
{
uint32_t old_MR0;
current_takt = takt;
if(cycle == 0ul)
{
ch3_8_pwm_stop_hw();
old_MR0 = 0;
return;
}
old_MR0 = LPC_PWM1->MR0;
LPC_PWM1->MR0 = cycle; /* set PWM cycle */
/* The LER will be cleared when the Match 0 takes place, in order to
load and execute the new value of match registers, all the PWMLERs need to
reloaded. all PWM latch enabled */
LPC_PWM1->MR1 = *p_offset_arr; /* set PWM offsets */
LPC_PWM1->MR2 = *(p_offset_arr+1);
LPC_PWM1->MR3 = *(p_offset_arr+2);
LPC_PWM1->MR4 = *(p_offset_arr+3);
LPC_PWM1->MR5 = *(p_offset_arr+4);
LPC_PWM1->MR6 = *(p_offset_arr+5);
LPC_PWM1->LER |= 0x0000007F;
if(old_MR0 == 0ul) // См. data sheet значение регистра после сброса
ch3_8_pwm_start_hw();
}
* ch3_8_hal.c
*
* Created on: 10.03.2012
* Author: Илья
*/
#include "LPC17xx.h"
#define MR0_INT (1 << 0)
#define MR1_INT (1 << 1)
#define MR2_INT (1 << 2)
#define MR3_INT (1 << 3)
#define MR4_INT (1 << 8)
#define MR5_INT (1 << 9)
#define MR6_INT (1 << 10)
#define TCR_CNT_EN 0x00000001
#define TCR_RESET 0x00000002
#define TCR_PWM_EN 0x00000008
#define PWMMR0I (1 << 0)
#define PWMMR0R (1 << 1)
#define PWMMR0S (1 << 2)
#define PWMMR1I (1 << 3)
#define PWMMR1R (1 << 4)
#define PWMMR1S (1 << 5)
#define PWMMR2I (1 << 6)
#define PWMMR2R (1 << 7)
#define PWMMR2S (1 << 8)
#define PWMMR3I (1 << 9)
#define PWMMR3R (1 << 10)
#define PWMMR3S (1 << 11)
#define PWMMR4I (1 << 12)
#define PWMMR4R (1 << 13)
#define PWMMR4S (1 << 14)
#define PWMMR5I (1 << 15)
#define PWMMR5R (1 << 16)
#define PWMMR5S (1 << 17)
#define PWMMR6I (1 << 18)
#define PWMMR6R (1 << 19)
#define PWMMR6S (1 << 20)
#define PWMSEL2 (1 << 2)
#define PWMSEL3 (1 << 3)
#define PWMSEL4 (1 << 4)
#define PWMSEL5 (1 << 5)
#define PWMSEL6 (1 << 6)
#define PWMENA1 (1 << 9)
#define PWMENA2 (1 << 10)
#define PWMENA3 (1 << 11)
#define PWMENA4 (1 << 12)
#define PWMENA5 (1 << 13)
#define PWMENA6 (1 << 14)
#define LER0_EN (1 << 0)
#define LER1_EN (1 << 1)
#define LER2_EN (1 << 2)
#define LER3_EN (1 << 3)
#define LER4_EN (1 << 4)
#define LER5_EN (1 << 5)
#define LER6_EN (1 << 6)
#define ACTIVE_TAKT_1_CH3 2
#define ACTIVE_TAKT_2_CH3 12
#define ACTIVE_TAKT_1_CH4 2
#define ACTIVE_TAKT_2_CH4 12
#define ACTIVE_TAKT_1_CH5 3
#define ACTIVE_TAKT_2_CH5 11
#define ACTIVE_TAKT_1_CH6 3
#define ACTIVE_TAKT_2_CH6 11
#define ACTIVE_TAKT_1_CH7 4
#define ACTIVE_TAKT_2_CH7 12
#define ACTIVE_TAKT_1_CH8 4
#define ACTIVE_TAKT_2_CH8 12
static uint_fast8_t current_takt;
//-----------------------------------------------------------------------------
static void pwm_ch3_8_irq_hw (void)
{
volatile uint32_t regVal;
volatile uint32_t load_value = 0ul;
//__disable_fault_irq();
//__disable_irq();
regVal = LPC_PWM1->IR;
LPC_PWM1->IR = regVal; /* clear interrupt flag on match 0 */
if( regVal & MR0_INT )
{
if(LPC_PWM1->MR1)
{
if(
current_takt == ACTIVE_TAKT_1_CH3 ||
current_takt == ACTIVE_TAKT_2_CH3
)
{
load_value |= 0x00008000;
}
}
if(LPC_PWM1->MR2)
{
if(
current_takt == ACTIVE_TAKT_1_CH4 ||
current_takt == ACTIVE_TAKT_2_CH4
)
{
load_value |= 0x00010000;
}
}
if(LPC_PWM1->MR3)
{
if(
current_takt == ACTIVE_TAKT_1_CH5 ||
current_takt == ACTIVE_TAKT_2_CH5
)
{
load_value |= 0x00020000;
}
}
if(LPC_PWM1->MR4)
{
if(
current_takt == ACTIVE_TAKT_1_CH6 ||
current_takt == ACTIVE_TAKT_2_CH6
)
{
load_value |= 0x00040000;
}
}
if(LPC_PWM1->MR5)
{
if(
current_takt == ACTIVE_TAKT_1_CH7 ||
current_takt == ACTIVE_TAKT_2_CH7
)
{
load_value |= 0x40000000;
}
}
LPC_GPIO0->FIOSET = load_value; /* swich on */
if(LPC_PWM1->MR6)
{
if(
current_takt == ACTIVE_TAKT_1_CH8 ||
current_takt == ACTIVE_TAKT_2_CH8
)
{
LPC_GPIO1->FIOSET = 0x00008000;
}
}
//return;
}
load_value = 0ul; // Обнуляю переменную перед тем как использовать ее еще раз
if( regVal & MR1_INT )
load_value |= 0x00008000;
if( regVal & MR2_INT )
load_value |= 0x00010000;
if( regVal & MR3_INT )
load_value |= 0x00020000;
if( regVal & MR4_INT )
load_value |= 0x00040000;
if( regVal & MR5_INT )
load_value |= 0x40000000;
LPC_GPIO0->FIOCLR = load_value;
if( regVal & MR6_INT )
LPC_GPIO1->FIOCLR = 0x00008000;
// __enable_fault_irq();
// __enable_irq();
}
//-----------------------------------------------------------------------------
static void ch3_8_init_hw(void)
{
// Out_3, Out_4
LPC_PINCON->PINSEL0 &= 0x3FFFFFFF; // P0.15 as GPIO port
LPC_PINCON->PINSEL1 &= 0xCFFFFFC0; // Настрою P0.16...P0.18, P0.30 как GPIO
// и обнулю выходы
LPC_PINCON->PINSEL2 &= 0x3FFFFFFF; // P1.15 as GPIO port
LPC_PINCON->PINMODE0 &= 0x3FFFFFFF; // not pull-... mode
LPC_PINCON->PINMODE0 |= 0x80000000;
LPC_PINCON->PINMODE1 &= 0xCFFFFFC0; // not pull-... mode
LPC_PINCON->PINMODE1 |= 0x2F00002A;
LPC_PINCON->PINMODE2 &= 0x3FFFFFFF; // not pull-... mode
LPC_PINCON->PINMODE2 |= 0x80000000;
LPC_PINCON->PINMODE_OD0 &= 0xBFF87FFF;
LPC_PINCON->PINMODE_OD1 &= 0xFFFF7FFF;
LPC_GPIO0->FIODIR |= 0x40078000;
LPC_GPIO0->FIOCLR = 0x40078000;
LPC_GPIO1->FIODIR |= 0x00008000;
LPC_GPIO1->FIOCLR = 0x00008000;
// Следующие две строчки должны быть одикаковы для всех каналов PWM
LPC_PWM1->TCR = TCR_CNT_EN | TCR_RESET; /* Counter enable, Counter Reset*/
LPC_PWM1->PR = 0ul; /* count frequency:Fpclk */
LPC_PWM1->MR0 = 0ul;
LPC_PWM1->MR1 = 0ul;
LPC_PWM1->MR2 = 0ul;
LPC_PWM1->MR3 = 0ul;
LPC_PWM1->MR4 = 0ul;
LPC_PWM1->MR5 = 0ul;
LPC_PWM1->MR6 = 0ul;
LPC_PWM1->PCR = 0ul;
LPC_PWM1->MCR = PWMMR0R | PWMMR0I | PWMMR1I | PWMMR2I |
PWMMR3I | PWMMR4I | PWMMR5I | PWMMR6I;
NVIC_SetPriority(PWM1_IRQn,0);
NVIC_EnableIRQ(PWM1_IRQn);
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_start_hw(void)
{
/* All single edge, all enable */
// LPC_PWM1->TCR &= ~(TCR_RESET);
// LPC_PWM1->TCR |= TCR_PWM_EN;
LPC_PWM1->TCR = 0x00000009; /* counter enable, ResetdisablePWM enable */
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_stop_hw(void)
{
LPC_PWM1->MR0 = 0ul; /* set PWM cycle */
/* set PWM offsets */
LPC_PWM1->MR1 = 0ul;
LPC_PWM1->MR2 = 0ul;
LPC_PWM1->MR3 = 0ul;
LPC_PWM1->MR4 = 0ul;
LPC_PWM1->MR5 = 0ul;
LPC_PWM1->MR6 = 0ul;
LPC_PWM1->LER |= 0x0000007F;
LPC_PWM1->TCR |= TCR_RESET; /* Counter Reset */
LPC_GPIO0->FIOCLR = 0x40078000;
LPC_GPIO1->FIOCLR = 0x00008000;
}
//-----------------------------------------------------------------------------
static void ch3_8_pwm_set_freq_offset_hw(uint32_t cycle, uint_fast8_t takt, uint32_t* p_offset_arr)
{
uint32_t old_MR0;
current_takt = takt;
if(cycle == 0ul)
{
ch3_8_pwm_stop_hw();
old_MR0 = 0;
return;
}
old_MR0 = LPC_PWM1->MR0;
LPC_PWM1->MR0 = cycle; /* set PWM cycle */
/* The LER will be cleared when the Match 0 takes place, in order to
load and execute the new value of match registers, all the PWMLERs need to
reloaded. all PWM latch enabled */
LPC_PWM1->MR1 = *p_offset_arr; /* set PWM offsets */
LPC_PWM1->MR2 = *(p_offset_arr+1);
LPC_PWM1->MR3 = *(p_offset_arr+2);
LPC_PWM1->MR4 = *(p_offset_arr+3);
LPC_PWM1->MR5 = *(p_offset_arr+4);
LPC_PWM1->MR6 = *(p_offset_arr+5);
LPC_PWM1->LER |= 0x0000007F;
if(old_MR0 == 0ul) // См. data sheet значение регистра после сброса
ch3_8_pwm_start_hw();
}
У меня шесть выходов ШИМа работающих на одной частоте 80...200 Гц. У них разный DC.
Управление периодом и DC сразу всех каналов ШИМа я осуществляю через функцию ch3_8_pwm_set_freq_offset_hw().
Из нее видно, что я сначала изменяю период ШИМа (регистр LPC_PWM1->MR0), затем меняю DC всех шести каналов,
затем устанавливаю биты в регистре LPC_PWM1->LER, разрешая при следующем переполнении таймера модуля PWM
переписать новые значения MR0... MR6 в теневые регистры модуля PWM.
И обычно так и происходит. Но вот иногда происходит такая картина как первом рисунке. Иногда - это примерно один раз в 20 минут и случайно на одном из шести каналов. Сейчас удалось поймать на первом(MR1).
Так кажется как будто не пришло прерывание от совпадения регистра MR1 и счетного регистра таймера PWM?
Или как будто в теневой регистр MR1 записалось значение больше чем MR0?
А может быть надо таймер PWM останавливать когда я обновляю регистры MR0....MR6, но в pdf ничего такого не написано?
Не знаю что и думать.....