Перейти к содержанию
    

Проблема С PWM на LPC1751

Добрый день господа форумчане.

Сталкивался ли кто нибудь с такой проблемой, что при формировании ШИM-сигнала при помощи модуля PWM в сигнале возникают периоды когда выход остается в высоком уровне ?

 

post-31472-1379066573_thumb.jpg

 

Код для работы с модулем PWM у меня такой:

 

/*
* 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 ничего такого не написано?

Не знаю что и думать.....

post-31472-1379066671_thumb.jpg

Изменено пользователем Илья_
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А может быть дело в том что от модуля PWM приходит одно прерывание, а событий по этому прерыванию у меня 7.

Я потом дополнительно выясняю что за событие вызвало прерывание.

Вдруг во время обработки одного прерывания приходит другое которое я как то пропускаю?

Думается мне что надо правильно воспользоваться критической секцией, но вот что то в голове нет понимания как правильно это сделать.

 

Может кто нибудь из уважаемых форумчан посоветует как это правильно сделать?

Заренее всем большое спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...