关于LPC17xx固件库定时器的Bug

2011-02-16 来自 · 5 评论 

这篇日志里我提到了LPC17xx定时器部分的固件库有Bug,具体为作为计数器模式的时候固件库工作不正常,检查代码后发现有几处错误,此问题已反馈给NXP。这几天收到了NXP的答复,他们承认了这个错误并已将这个问题反馈给了相关的工程师。在报告Bug的过程中,我也尝试着修复这个Bug。下面是往来邮件和附件,包括问题的重现和我修改后的代码。

From: Case Notification [mailto:noreply@salesforce.com]
Sent: 2011 Feb 12 1:18 PM
To: Eric Wang
Subject: Case # 00001236: Bugs in LPC17xx Firmware library has been assigned to you.
*** New Case Assignment Notification ***
Following Case has been assigned to you:
Company:
Contact:
Case Number: 00001236
Subject: Bugs in LPC17xx Firmware library
Description: Related product: Microcontrollers, Cortex-M3 (32-bit), LPC1700
There might be a bug in LPC17xx Firmware library that when timer works in counter mode, the firmware library doesn’t work as expected. Some register names in the firmware code might be wrong(i.e. CCR and CTCR), and parameter check in the header files is also a mistake since it totally ignored counter falling mode etc.
bug fixed and update is expected.
Click on the link to access the Case: https://eu1.salesforce.com/500D000000E4byl
Hi Wang,
We just got a case from you.Thanks for your question.
Can you give more detail about your question?
How did you get the lib? From our website?
Lib can not work as expected, what are you expected?Is there any demo code?
You mean ” Some register names in the firmware code might be wrong(i.e. CCR and CTCR), and parameter check in the header files is also a mistake since it totally ignored counter falling mode etc.” Could you point it clearly?
If you provide more info, we could fix it asap.
Best Regards,
Eric Wang 王 超
PAE, MCU
NXP Semiconductor
Hi Wang,
Thank you for reply.
The lib is download from http://ics.nxp.com/support/documents/microcontrollers/?scope=LPC17xx , marked “LPC17xx CMSIS-Compliant Standard Peripheral Firmware Driver Library (GNU, Keil, IAR) “.
The user’s manual(UM10360) mentioned that timers in lpc17xx could be used as counters, which I think that on every certain edge on the certain pin would increase the counter by 1.
I’ll attach my demo project and you should extract the full library into it before run. I tested it with LPC1768.
I tried to correct the mistake and it’s also attached, I modified these lines
File lpc17xx_timer.h, Line 142
File lpc17xx_timer.c, Line 320, 321, 344, 346
I have comments on these lines and they begin with”//!!”
I’m not sure if there are more mistakes and you should have a double check on it.
Regards,
王盛业
复旦大学复旦学院克卿书院 10607班
复旦大学信息科学与工程学院 电子信息科学类
Hi,
Thanks for your info. I have a look and find following should be mistake. I will forward to related engineer to fix.
File lpc17xx_timer.h, Line 142
File lpc17xx_timer.c, Line 320, 321, 344, 346
For counter function, I will check and give you feedback at convenience.
Best Regards,
Eric Wang 王 超
PAE, MCU
NXP Semiconductor

补充:后来又收到了NXP的邮件,算是总结性的答复。大致内容和上面的类似,然而可能我表达不清他以为我报告器件有Bug。学好英语很重要……

Dear Shengye,
Your inquiry is resolved for your case 00001236: Bugs in LPC17xx Firmware library
Solution answer:
Hi Shengye,
Thanks for your mail.
I check the lib which can downlaod from link http://ics.nxp.com/support/documents/microcontrollers/zip/lpc17xx.cmsis.driver.library.zip .
For line 142 in lpc17xx_timer.h, #define PARAM_TIM_MODE_OPT(MODE) ((MODE == TIM_TIMER_MODE)||(MODE == TIM_COUNTER_RISING_MODE)\
|| (MODE == TIM_COUNTER_RISING_MODE)||(MODE == TIM_COUNTER_RISING_MODE)) should be
#define PARAM_TIM_MODE_OPT(MODE) ((MODE == TIM_TIMER_MODE)||(MODE == TIM_COUNTER_RISING_MODE)\
|| (MODE == TIM_COUNTER_FALLING_MODE)||(MODE == TIM_COUNTER_ANY_MODE)) .
For line 320, 344, 346 in lpc17xx_timer.c, TIMx->CCR should be TIMx->CTCR .
line 321 should beTIMx->CTCR |= TimerCounterMode;
I will forward to related engineer check and fix.
Btw, you refer that Counter register can not be incremented after related edge. Pls confirm that he frequency of the CAP input can not exceed one quarter of the PCLK clock. If exceed, count will not identify the edge.
Please let us know if this does not resolve your inquiry. Your ticket will remain closed if we do not hear from you.
Registration in my.NXP (www.nxp.com/my) is required for you to check your question status and/or submit a follow-up to your question. For any reference to this question, use the following number:
* Case# 00001236.
*** TIPS ***
- Please do not reply to this email, it has been sent automatically.
- Modify your junk or spam setting to allow incoming “nxp.com” e-mail addresses.
- Add the sender, “NXP Technical Support” to your list of known contacts.
Best Regards,
The NXP Technical Support Team
NXP Semiconductors
附件:bug demo
仅供大家参考,希望下一个固件库的更新版本中能修复这个问题。

学习LPC17xx – IIC

2011-02-12 来自 · 2 评论 

这是IIC操作EEPROM的例子。在调试过程中,误将从机地址写为0×01010000而导致出错,这是十六进制而非二进制!

  • 千万别傻傻地把从机地址弄错,0×01010000这种错误不能犯!这是十六进制,不是二进制!

代码如下:

#include <lpc17xx.h>
#include <stdint.h>
#include "lpc17xx_libcfg.h"
#include <debug_frmwrk.h>
#include <lpc17xx_pinsel.h>
#include <lpc17xx_i2c.h>
 
uint32_t _DGETNUM(uint8_t cnt)
{
	uint32_t rtn = 0;
	while(cnt--) {
		rtn = rtn * 10 + (_DG - '0');
	}
	return rtn;
}
 
uint8_t buf[100];
 
uint32_t writeEEPROM(uint32_t len)
{
	I2C_M_SETUP_Type i2ccfg;
	i2ccfg.sl_addr7bit = 0x50;
	i2ccfg.tx_data = buf;
	i2ccfg.tx_length = len;
	i2ccfg.tx_count = 0;
	i2ccfg.rx_data = NULL;
	i2ccfg.rx_length = 0;
	i2ccfg.rx_count = 0;
	i2ccfg.retransmissions_max = 1;
	i2ccfg.retransmissions_count = 0;
	i2ccfg.status = 0;
   	i2ccfg.callback = NULL;
	return I2C_MasterTransferData(LPC_I2C0, &i2ccfg, I2C_TRANSFER_POLLING) == SUCCESS;
}
 
uint32_t readEEPROM(uint32_t len)
{
	I2C_M_SETUP_Type i2ccfg;
	i2ccfg.sl_addr7bit = 0x50;
	i2ccfg.tx_data = buf;
	i2ccfg.tx_length = 1;
	i2ccfg.tx_count = 0;
	i2ccfg.rx_data = buf + 1;
	i2ccfg.rx_length = len;
	i2ccfg.rx_count = 0;
	i2ccfg.retransmissions_max = 3;
	i2ccfg.retransmissions_count = 0;
	i2ccfg.status = 0;
   	i2ccfg.callback = NULL;
	return I2C_MasterTransferData(LPC_I2C0, &i2ccfg, I2C_TRANSFER_POLLING) == SUCCESS;
}
 
int main(void)
{
	char cmd;
	int i;
	uint8_t cnt, addr; 
	PINSEL_CFG_Type pincfg;
	debug_frmwrk_init();
	_DBG_("I2C EEPROM Test(W to write and R to read)");
 
	pincfg.Portnum = PINSEL_PORT_0;
	pincfg.Pinnum = PINSEL_PIN_27;
	pincfg.Funcnum = PINSEL_FUNC_1;
	pincfg.Pinmode = 0;
	pincfg.OpenDrain = 0;
	PINSEL_ConfigPin(&pincfg);
 
	pincfg.Portnum = PINSEL_PORT_0;
	pincfg.Pinnum = PINSEL_PIN_28;
	pincfg.Funcnum = PINSEL_FUNC_1;
	pincfg.Pinmode = 0;
	pincfg.OpenDrain = 0;
	PINSEL_ConfigPin(&pincfg);
 
	I2C_Init(LPC_I2C0, 100000);
	I2C_Cmd(LPC_I2C0, ENABLE);
	while(1) {
		_DBG_("Command(C), Length(2), Address(3)");
		cmd = _DG;
		cnt = _DGETNUM(2);
		addr = _DGETNUM(3);
		buf[0] = addr;
		switch(cmd) {
			case 'R':
				if (!readEEPROM(cnt)) _DBG_("Failed");
				for(i = 1; i <= cnt; ++ i) _DBC(buf[i]);
				_DBG_("");
				break;
			case 'W':
				i = 0;
				while(cnt --) {
					buf[++ i] = _DG;
					_DBG_("");
					if (i == 8 || cnt == 0) {
						if (!writeEEPROM(i + 1)){
							_DBG_("Failed");
							i = -1;
							break;
						} else {
							buf[0] += 8;
							i = 0;
						}
					}
				}
				if (i != -1) _DBG_("Successed");
				break;
		}
	}
}

学习LPC17xx – RTC

2011-02-12 来自 · 一条评论 

  • 一开始时RTC走的特别慢,而且时间间隔不确定,可能是由于某些复位值不确定。
  • 一些复位值不确定的寄存器可能要另外初始化(不确定)
#include <lpc17xx.h>
#include <stdint.h>
#include "lpc17xx_libcfg.h"
#include <debug_frmwrk.h>
#include <lpc17xx_rtc.h>
 
uint32_t _DGETNUM(uint8_t cnt)
{
	uint32_t rtn = 0;
	while(cnt--) {
		rtn = rtn * 10 + (_DG - '0');
	}
	return rtn;
}
 
RTC_TIME_Type rtctim;
 
void readrtctim()
{
	_DBG("Second : "); rtctim.SEC = _DGETNUM(2); _DBD32(rtctim.SEC); _DBG_("");
	_DBG("Minute : "); rtctim.MIN = _DGETNUM(2); _DBD32(rtctim.MIN); _DBG_("");
	_DBG("Hour   : "); rtctim.HOUR = _DGETNUM(2); _DBD32(rtctim.HOUR); _DBG_("");
	_DBG("D of M : "); rtctim.DOM = _DGETNUM(2); _DBD32(rtctim.DOM); _DBG_("");
	_DBG("D of W : "); rtctim.DOW = _DGETNUM(2); _DBD32(rtctim.DOW); _DBG_("");
	_DBG("D of Y : "); rtctim.DOY = _DGETNUM(3); _DBD32(rtctim.DOY); _DBG_("");
 	_DBG("Month  : "); rtctim.MONTH = _DGETNUM(2); _DBD32(rtctim.MONTH); _DBG_("");
	_DBG("Year   : "); rtctim.YEAR = _DGETNUM(4); _DBD32(rtctim.YEAR); _DBG_("");
	_DBG_("**********************************************************************");
}
 
void writertctim()
{
	_DBG("Second : "); _DBD32(rtctim.SEC); _DBG_("");
	_DBG("Minute : "); _DBD32(rtctim.MIN); _DBG_("");
	_DBG("Hour   : "); _DBD32(rtctim.HOUR); _DBG_("");
	_DBG("D of M : "); _DBD32(rtctim.DOM); _DBG_("");
	_DBG("D of W : "); _DBD32(rtctim.DOW); _DBG_("");
	_DBG("D of Y : "); _DBD32(rtctim.DOY); _DBG_("");
 	_DBG("Month  : "); _DBD32(rtctim.MONTH); _DBG_("");
	_DBG("Year   : "); _DBD32(rtctim.YEAR); _DBG_("");
	_DBG_("**********************************************************************");
}
 
int main(void)
{
	char cmd;
	uint32_t ch;
	debug_frmwrk_init();
	_DBG_("RTC Test Time(S to set and G to Get), Reg(W to write and R to read)");
	RTC_Init(LPC_RTC);
	RTC_ResetClockTickCounter(LPC_RTC);
	RTC_Cmd(LPC_RTC, ENABLE);
	RTC_CalibCounterCmd(LPC_RTC, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_SECOND, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_MINUTE, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_HOUR, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_DAYOFWEEK, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_DAYOFMONTH, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_DAYOFYEAR, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_MONTH, DISABLE);
	RTC_CntIncrIntConfig(LPC_RTC, RTC_TIMETYPE_YEAR, DISABLE);	
	while(1) {
		cmd = _DG;
		switch(cmd) {
			case 'S':
				readrtctim();
				RTC_SetFullTime(LPC_RTC, &rtctim);
				break;
			case 'G':
				RTC_GetFullTime(LPC_RTC, &rtctim);
				writertctim();
				break;
			case 'W':
				_DBG("Channel : ");
				ch = _DGETNUM(1);
				_DBD(ch); _DBG_("");
				RTC_WriteGPREG(LPC_RTC, ch, _DGETNUM(10));
				_DBD32(RTC_ReadGPREG(LPC_RTC, ch)); _DBG_("");
				break;
			case 'R':
				_DBG("Channel : ");
				ch = _DGETNUM(1);
				_DBD(ch); _DBG_("");
				_DBD32(RTC_ReadGPREG(LPC_RTC, ch)); _DBG_("");
				break; 
		}
	}
}

学习LPC17xx – 看门狗

2011-02-12 来自 · 留下评论 

看门狗能在芯片运行错误的时候复位系统。LPC17xx的看门狗提供了一个“中断模式”,当看门狗超时时进入中断。然而这个中断不能被关闭,而且实际应用的时候不应该使用中断模式,仅是为了调试方便。

  • 若设置成中断模式,那么中断标志不能被软件清零,除非复位。要禁用中断,需要在NVIC中关闭。中断模式的作用就是为了调试看门狗,不让器件复位。

代码通过触发一个外部中断让程序进入死循环而不能正常喂狗,而迫使看门狗复位。

 
#include <lpc17xx.h>
#include "lpc17xx_libcfg.h"
#include <debug_frmwrk.h>
#include <lpc17xx_gpio.h>
#include <lpc17xx_nvic.h>
#include <lpc17xx_systick.h>
#include <stdint.h>
#include <lpc17xx_exti.h>
#include <lpc17xx_pinsel.h>
#include <lpc17xx_wdt.h>
 
volatile uint8_t led7;
 
volatile uint32_t SysTickCnt;
 
void EINT3_IRQHandler(void)
{
	_DBG_("Int Triggered");
	//dead here
	while(1);
}
 
void SysTick_Handler(void) {
	SysTickCnt++;
}
 
int main(void)
{
	uint32_t prv;
	uint8_t i;
	PINSEL_CFG_Type pincfg;
	debug_frmwrk_init();
	_DBG_("System Start/Reset");
	GPIO_SetDir(2, 0x000000FF, 1);
	GPIO_SetDir(2, 1 << 11, 0);
	SYSTICK_InternalInit(10); //the maximum value should not exceed the 24 bit systick counter
	SYSTICK_Cmd(ENABLE);
	SYSTICK_IntCmd(ENABLE);
   	GPIO_IntCmd(2, 1 << 10, 0);
 
	pincfg.Portnum = PINSEL_PORT_2;
	pincfg.Pinnum = PINSEL_PIN_10;
	pincfg.Funcnum = PINSEL_FUNC_0;
	pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
	pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
 
	PINSEL_ConfigPin(&pincfg);
 
	NVIC_SetPriority(SysTick_IRQn, 0);
	NVIC_SetPriority(EINT3_IRQn, 1);
	NVIC_EnableIRQ(EINT3_IRQn);
 
	WDT_Init(WDT_CLKSRC_IRC, WDT_MODE_RESET);
	WDT_Start(100000);
 
	while(1) {
		for(i = 0; i <= 7; ++ i) {
			GPIO_SetValue(2, 1 << i);
			prv = SysTickCnt;
			while(SysTickCnt - prv < 10);
			GPIO_ClearValue(2, 1 << i);
			WDT_Feed();
		}
	}
}

学习LPC17xx – DAC

2011-02-12 来自 · 留下评论 

LPC17xx的DAC操作比较简单。除此外它还支持DMA访问,所以可能可以方便的合成数字信号。

  • 若没有选择对应的引脚,那么DAC不会启动,对其寄存器访问会产生硬错误

代码:从0开始,每0.1秒将DAC的值增加1,同时采集ADC的值输出到串口。只要将DAC输出和ADC输入连接,就可以看到采样值。

#include <lpc17xx.h>
#include "lpc17xx_libcfg.h"
#include <debug_frmwrk.h>
#include <lpc17xx_nvic.h>
#include <lpc17xx_pinsel.h>
#include <lpc17xx_dac.h>
#include <lpc17xx_adc.h>
#include <lpc17xx_systick.h>
//#include <core_cm3.h>
 
volatile int SysTickCnt;
 
void SysTick_Handler(void) {
	SysTickCnt++;
}
 
int main(void)
{
	PINSEL_CFG_Type pincfg;
	int prv;
	int cur = 0;
 
	debug_frmwrk_init();
	_DBG_("DAC Test");
 
	//PWM Pins and Channels
 
	pincfg.Portnum = PINSEL_PORT_0;
	pincfg.Pinnum = PINSEL_PIN_26;
	pincfg.Funcnum = PINSEL_FUNC_2;
	pincfg.Pinmode = PINSEL_PINMODE_TRISTATE;
	pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	PINSEL_ConfigPin(&pincfg);
 
	DAC_Init(LPC_DAC);
	DAC_UpdateValue(LPC_DAC, (1 << 10) - 1);
 
	SYSTICK_InternalInit(10); //the maximum value should not exceed the 24 bit systick counter
	SYSTICK_Cmd(ENABLE);
	SYSTICK_IntCmd(ENABLE);
 
	pincfg.Portnum = PINSEL_PORT_1;
	pincfg.Pinnum = PINSEL_PIN_31;
	pincfg.Funcnum = PINSEL_FUNC_3;
	pincfg.Pinmode = PINSEL_PINMODE_TRISTATE;
	pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
 
	PINSEL_ConfigPin(&pincfg);
 
	ADC_Init(LPC_ADC, 200000);
	ADC_ChannelCmd(LPC_ADC, 5, ENABLE);
	ADC_BurstCmd(LPC_ADC, ENABLE);
	ADC_StartCmd(LPC_ADC, ADC_START_CONTINUOUS);
	while(1) {
		while(!ADC_ChannelGetStatus(LPC_ADC, 5, 1));
		_DBD16(ADC_ChannelGetData(LPC_ADC, 5));	_DBG_("");
		prv = SysTickCnt;
		while(SysTickCnt < prv + 10);
		cur = (cur + 1) & ((1 << 10) - 1);
		DAC_UpdateValue(LPC_DAC, cur);
	}
 
}

第 1 页 共 4 页1234