【TI首届低功耗设计大赛】 之电子产品运行数据记录仪
在研发电子产品的过程中可能会遇到自己设计的产品运行不稳定,经过出现异常现象,查看代码又发现不了问题。这时候一搬会弄一台笔记本,把串口连接到新产品上,记录新产品运行时的日志。这种方法对测试环境有一定的局限性,比如强干扰的环境、空间受限的环境、室外环境等,如果需要长时间记录,笔记本还需要配备电源,在没无法提供电源接入的场合笔记本就无法胜任此工作。
另外笔记本的测试成本过高,在多个产品同时测试时提供大量的笔记本也是不现实滴。
本方案是利用MSP430FR5969优越性能,通过一条串口线接收新产品的日志数据,实时保存到FRAM中,虽然新产品测试时的日志文件很大,但通常我们更关心的是出故障时的一段数据,通过反复重写保留最新日志数据。MSP430FR5969不仅功耗低而且写入速度也非常快,所以可以使用一个小小的钮扣电池来提供电能。这样记录仪的体积会变的很小,非常适用一些空间受限的场合。
今天一整天都在赶活动,快饿死了,废话不说,上代码:
-
- #include <stdint.h>
- #include <string.h>
- #include <msp430.h>
- #include "mcu_config.h"
- #include "hal_timer.h"
- #define FRAM_STORE_START_ADDRESS 0xD000 //数据存储起始地址
- #define OFFSET_LEN 4 //offset自身的长度(字节)
- #define MAX_STORE_LEN 10000 //最大存储深度
- #define BUFFER_LEN 128
- uint32_t *FRAM_offset_write_ptr; //写入偏移量的指针
- char *FRAM_str_write_ptr; //写入字符串的指针
- uint8_t str_counter = 0; //存储数据计数器
-
- uint8_t clear_frame_command[] = "clear fram";
- uint8_t print_frame_command[] = "print fram";
- uint8_t buf[BUFFER_LEN];
- uint8_t buf_index = 0;
- uint32_t fram_read_offset(void)
- {
- uint32_t fram_store_address_offset; //数据偏移地址,保留4个字节用来存储修改后的偏移地址
- FRAM_offset_write_ptr = (uint32_t *)(FRAM_STORE_START_ADDRESS); //初始化读取fram_store_address_offset 的地址
- fram_store_address_offset = *FRAM_offset_write_ptr;
- if(fram_store_address_offset == 0xffffffff) //第一次上电
- {
- fram_store_address_offset = OFFSET_LEN;
- }
- return fram_store_address_offset;
- }
- void fram_write_offset(uint32_t offset)
- {
- FRAM_offset_write_ptr = (uint32_t *)(FRAM_STORE_START_ADDRESS); //初始化读取fram_store_address_offset 的地址
- *FRAM_offset_write_ptr = offset;
- }
- void fram_write_byte(uint8_t c)
- {
- uint32_t offset = fram_read_offset();
- FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + offset ); //初始化数据存储地址
- *FRAM_str_write_ptr++ = c; //将数据写入FRAM
- if(offset++ > MAX_STORE_LEN)
- {
- offset = OFFSET_LEN; //从零开始记录
- } //更新指针偏移
- fram_write_offset(offset);
- }
- void fram_write_n_byte(uint8_t *buf,uint16_t len)
- {
- uint16_t i;
- for(i=0;i<len;i++)
- {
- fram_write_byte(buf[i]);
- }
- }
- void fram_write_char(char c)
- {
- fram_write_byte((uint8_t)c);
- }
- void fram_write_str(char * str)
- {
- uint16_t len = strlen(str);
- uint32_t offset = fram_read_offset();
- FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + offset ); //初始化数据存储地址
- while(*str)
- {
- *FRAM_str_write_ptr++ = *str++; //将数据写入FRAM
- }
- offset += len; //更新指针偏移
- fram_write_offset(offset);
- }
- void uart_init(void)
- {
- // Configure GPIO
- P1OUT &= ~BIT0; // Clear P1.0 output latch
- P1DIR |= BIT0; // For LED on P1.0
- P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
- P2SEL0 &= ~(BIT0 | BIT1);
- // Configure USCI_A0 for UART mode
- UCA0CTLW0 = UCSWRST; // Put eUSCI in reset
- UCA0CTL1 |= UCSSEL__SMCLK; // CLK = SMCLK
- UCA0BR0 = 8; // 1000000/115200 = 8.68
- UCA0MCTLW = 0xD600; // 1000000/115200 - INT(1000000/115200)=0.68
- // UCBRSx value = 0xD6 (See UG)
- UCA0BR1 = 0;
- UCA0CTL1 &= ~UCSWRST; // release from reset
- UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
- }
- void uart_tx_byte(uint8_t b)
- {
- while(!(UCA0IFG & UCTXIFG));
- UCA0TXBUF = b; // Load data onto buffer
- }
- void uart_tx_n_bytes(uint8_t *buf,uint16_t len)
- {
- uint16_t i;
- for(i=0;i<len;i++)
- {
- uart_tx_byte(buf[i]);
- }
- }
- void uart_tx_str(char * str)
- {
- while(*str)
- {
- uart_tx_byte(*str++);
- }
- }
- void fram_clear(void)
- {
- uint32_t i;
- uint32_t offset = fram_read_offset();
- //FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS); //初始化数据存储地址
- for(i=0;i<MAX_STORE_LEN;i++)
- {
- if(i%128 == 0)
- {
- FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + i); //初始化数据存储地址
- }
- *FRAM_str_write_ptr++ = 0xff;
- }
- uart_tx_str("done");
- //将数据写入FRAM
- }
- void print_all_str(void)
- {
- uint32_t i;
- uint32_t len = fram_read_offset(); //获得存储的数据长度
- uint8_t * start_ptr = (uint8_t *)(FRAM_STORE_START_ADDRESS + OFFSET_LEN);
- for(i=0;i<len;i++)
- {
- uart_tx_byte(*start_ptr++);
- }
- }
- uint8_t compare(uint8_t * a,uint8_t *b,uint8_t len)
- {
- uint8_t i;
- for(i=0;i< len;i++)
- {
- if(a[i] != b[i])
- {
- return 0;
- }
- }
- return 1;
- }
- int main(void)
- {
- uint16_t i;
- WDTCTL = WDTPW | WDTHOLD; // Stop watchdog
-
- // Configure GPIO
- PJOUT &= ~BIT0; // Clear P1.0 output latch
- PJDIR |= BIT0; // For LED on P1.0
- PM5CTL0 &= ~LOCKLPM5;
- __delay_cycles(65500);
- // fram_write("hello eeworld!\n");
- // fram_write("msp430fr5969!\n");
- uart_init();
- print_all_str();
-
- while(1)
- {
- __bis_SR_register(LPM0_bits | GIE); // Enter LPM0, interrupts enabled
- if(compare(buf,clear_frame_command,strlen(clear_frame_command)))
- {
- fram_clear();
- buf_index = 0;
- }
- else if(compare(buf,print_frame_command,strlen(print_frame_command)))
- {
- print_all_str();
- buf_index = 0;
- }
- else
- {
- fram_write_n_byte(buf,buf_index);
- buf_index = 0;
- }
-
- }
- }
- #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
- #pragma vector=USCI_A0_VECTOR
- __interrupt void USCI_A0_ISR(void)
- #elif defined(__GNUC__)
- void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
- #else
- #error Compiler not supported!
- #endif
- {
- switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
- {
- case USCI_NONE: break;
- case USCI_UART_UCRXIFG:
- buf[buf_index] = UCA0RXBUF;
- UCA0TXBUF = buf[buf_index];
- if(buf[buf_index] == '\n')
- {
- __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
- }
- buf_index++;
- break;
- case USCI_UART_UCTXIFG: break;
- case USCI_UART_UCSTTIFG: break;
- case USCI_UART_UCTXCPTIFG: break;
- }
- }
视频讲解
本帖最后由 littleshrimp 于 2014-12-29 08:31 编辑