LPC824 microcontroller ADC demo HardFault problem - embedded

I'm trying to program LPC824 microcontroller board ([https://www.switch-science.com/catalog/2265/][1]) with LPCOpen.
I'm using it with LPCLink 2 debugger board.
My goal is to get some information from the "pressure sensor" with an ADC.
My code stops with a HardFault when executing a NVIC_EnableIRQ function(on line: 92).
If I don't use "NVIC interrupt controller" then my code works and I can get value from sensor with ADC.
What I am doing wrong?
Here is my adc.c code:
#include "board.h"
static volatile int ticks;
static bool sequenceComplete = false;
static bool thresholdCrossed = false;
#define TICKRATE_HZ (100) /* 100 ticks per second */
#define BOARD_ADC_CH 2
/**
* #brief Handle interrupt from ADC sequencer A
* #return Nothing
*/
void ADC_SEQA_IRQHandler(void) {
uint32_t pending;
/* Get pending interrupts */
pending = Chip_ADC_GetFlags(LPC_ADC);
/* Sequence A completion interrupt */
if (pending & ADC_FLAGS_SEQA_INT_MASK) {
sequenceComplete = true;
}
/* Threshold crossing interrupt on ADC input channel */
if (pending & ADC_FLAGS_THCMP_MASK(BOARD_ADC_CH)) {
thresholdCrossed = true;
}
/* Clear any pending interrupts */
Chip_ADC_ClearFlags(LPC_ADC, pending);
}
/**
* #brief Handle interrupt from SysTick timer
* #return Nothing
*/
void SysTick_Handler(void) {
static uint32_t count;
/* Every 1/2 second */
if (count++ == TICKRATE_HZ / 2) {
count = 0;
Chip_ADC_StartSequencer(LPC_ADC, ADC_SEQA_IDX);
}
}
/**
* #brief main routine for ADC example
* #return Function should not exit
*/
int main(void) {
uint32_t rawSample;
int j;
SystemCoreClockUpdate();
Board_Init();
/* Setup ADC for 12-bit mode and normal power */
Chip_ADC_Init(LPC_ADC, 0);
Chip_ADC_Init(LPC_ADC, ADC_CR_MODE10BIT);
/* Need to do a calibration after initialization and trim */
Chip_ADC_StartCalibration(LPC_ADC);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC))) {
}
/* Setup for maximum ADC clock rate using sycnchronous clocking */
Chip_ADC_SetClockRate(LPC_ADC, ADC_MAX_SAMPLE_RATE);
Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX,
(ADC_SEQ_CTRL_CHANSEL(BOARD_ADC_CH) | ADC_SEQ_CTRL_MODE_EOS));
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC2);
Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);
/* Setup threshold 0 low and high values to about 25% and 75% of max */
Chip_ADC_SetThrLowValue(LPC_ADC, 0, ((1 * 0xFFF) / 4));
Chip_ADC_SetThrHighValue(LPC_ADC, 0, ((3 * 0xFFF) / 4));
Chip_ADC_ClearFlags(LPC_ADC, Chip_ADC_GetFlags(LPC_ADC));
Chip_ADC_EnableInt(LPC_ADC,
(ADC_INTEN_SEQA_ENABLE | ADC_INTEN_OVRRUN_ENABLE));
Chip_ADC_SelectTH0Channels(LPC_ADC, ADC_THRSEL_CHAN_SEL_THR1(BOARD_ADC_CH));
Chip_ADC_SetThresholdInt(LPC_ADC, BOARD_ADC_CH, ADC_INTEN_THCMP_CROSSING);
/* Enable ADC NVIC interrupt */
NVIC_EnableIRQ(ADC_SEQA_IRQn);
Chip_ADC_EnableSequencer(LPC_ADC, ADC_SEQA_IDX);
SysTick_Config(SystemCoreClock / TICKRATE_HZ);
/* Endless loop */
while (1) {
/* Sleep until something happens */
__WFI();
if (thresholdCrossed) {
thresholdCrossed = false;
printf("********ADC threshold event********\r\n");
}
/* Is a conversion sequence complete? */
if (sequenceComplete) {
sequenceComplete = false;
/* Get raw sample data for channels 0-11 */
for (j = 0; j < 12; j++) {
rawSample = Chip_ADC_GetDataReg(LPC_ADC, j);
/* Show some ADC data */
if (rawSample & (ADC_DR_OVERRUN | ADC_SEQ_GDAT_DATAVALID)) {
printf("Chan: %d Val: %d\r\n", j, ADC_DR_RESULT(rawSample));
printf("Threshold range: 0x%x ",
ADC_DR_THCMPRANGE(rawSample));
printf("Threshold cross: 0x%x\r\n",
ADC_DR_THCMPCROSS(rawSample));
printf("Overrun: %s ",
(rawSample & ADC_DR_OVERRUN) ? "true" : "false");
printf("Data Valid: %s\r\n\r\n",
(rawSample & ADC_SEQ_GDAT_DATAVALID) ?
"true" : "false");
}
}
}
}
}

Hard fault usually means that you try to execute code outside allowed addresses. If you have not registered the interrupt in the vector table but enabled it, the MCU will jump to whatever address that's written there instead, after which the program crashes.
How to fix that depends on tool chain. Assuming LPCXpresso, you have several options to set up libraries (I don't know about LPCOpen specifically), so where to find the vector table is different from case to case. However, this works quite similar on most MCUs, ARM or not. Somewhere in a "crt start-up" file you should have something along the lines of this:
void (* const g_pfnVectors[])(void) = ...
This is an array of function pointers which will be the vector table allocated in memory at address 0 on Cortex M. You have to place your function at the relevant interrupt vector. For example it may say something like
PIN_INT0_IRQHandler, // PIO INT0
If that's the interrupt you should implement, then you replace that line:
#include "my_irq_stuff.h"
...
void (* const g_pfnVectors[])(void) =
...
my_INT0, // PIO INT0
Assuming my_irq_stuff.h contains the function prototype my_INT0 for the interrupt service routine. The actual routine should be implemented in the corresponding .c file.

Related

STM32F4 UART Rx Interrupt Example Code

I've been trying to implement a basic per-byte UART Rx Interrupt on a STM32F4 board using HAL skeleton code generated by STMCubeMX version 4.26.0
Quite simply - I want to receive a character in UART1 via an Rx interrupt and transmit it on UART 6
I have successfully implemented a polled version of what I want to achieve
uint8_t in_usart1[10];
HAL_StatusTypeDef usart1_status;
usart1_status = HAL_UART_Receive(&huart1, in_usart1, 1, 1);
if (usart1_status != HAL_TIMEOUT)
{
HAL_UART_Transmit(&huart6, in_usart1, 1, 100);
}
I've enabled the UART 1 NVIC interrupt in STMCubeMX and stm32f4xx_it.c contains the IRQ handler which I've added my own user handler to:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAX_USART1_IRQHandler(&huart1); /* My Handler */
/* USER CODE END USART1_IRQn 1 */
}
I've seen lot's of commentary about UART_Receive_IT() - but I suspect this is based on older versions of HAL due to UART_Receive_IT() being defined in stm32f4xx_hal_uart.c
My suspicion is that I need to enable to interrupt / clear the interrupt flag as when I debug, USART1_IRQHandler() is NEVER called
Does any one have any code that demonstrates what I am trying to achieve? My google-foo has failed me
EDIT:
I've gotten a little closer... In main.c I added (comments are existing code)
/* USER CODE BEGIN PV */
uint8_t rx_buffer;
/* USER CODE END PV */
...
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 10);
/* USER CODE END 2 */
And then created:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
HAL_UART_Transmit(&huart6, &rx_buffer, 1, 100);
}
}
Now the Rx interrupt gets fired - but it's a bit flakey on the USART6 Tx, and the Rx interrupt only gets fired once
Do not block HAL_UART_RxCpltCallback for a long time! Just set a flag and check it and then send data from the main function.
And rx_buffer is variable so correct call HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
For anybody stumbling across this question, the answer is embarrassingly simple. I have two UARTs - One I was using an Rx Interrupt, and the other using DMA.
Turns out the one I thought I had configured for Interrupt was actually configured for DMA and visa-versa...
In STMCubeMX
- USART1 (RS485) has DMA Tx and DMA Rx enabled
- USART6 (Debug - RS232) has global interrupt enabled
In main.c
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
/* USER CODE END 2 */
I have a user_main.c which has the following code:
#include <string.h>
#include "stm32f4xx_hal.h"
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart6;
UART_HandleTypeDef *debug_uart(void)
{
return &huart6;
}
UART_HandleTypeDef *rs485_uart(void)
{
return &huart1;
}
#define BUFFER_SIZE 1
uint8_t debug_rx_buffer[BUFFER_SIZE];
uint8_t debug_tx_buffer[BUFFER_SIZE];
uint8_t rs485_rx_buffer[BUFFER_SIZE];
uint8_t rs485_tx_buffer[BUFFER_SIZE];
static void rs485_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit_DMA(rs485_uart(), tx_buffer, len);
}
static void debug_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit(debug_uart(), tx_buffer, len, 1000);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
memcpy(rs485_tx_buffer, debug_rx_buffer, BUFFER_SIZE);
rs485_tx(rs485_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
}
else if (huart == rs485_uart())
{
memcpy(debug_tx_buffer, rs485_rx_buffer, BUFFER_SIZE);
debug_tx(debug_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
}
else if (huart == rs485_uart())
{
}
}
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
}
The memcpy()'s may not be strictly required, but they do provide a level of isolation between all the buffers. Technically, there probably should be semaphores providing even more protection...
Note that I DO NOT use HAL_UART_Transmit_IT() for the debug UART - If you want to use HAL_UART_Transmit_IT (i.e. interrupt generated on completion of Tx), you will need to write code that handles transmission of characters from a circular buffer

STM32F4: SD-Card using FatFs and USB fails

(also asked on SE: Electrical Engineering)
In my application, I've set up a STM32F4, SD-Card and USB-CDC (all with CubeMX).
Using a PC, I send commands to the STM32, which then does things on the SD-Card.
The commands are handled using a "communicationBuffer" (implemented by me) which waits for commands over USB, UART, ... and sets a flag, when a \n character was received. The main loop polls for this flag and if it is set, a parser handles the command. So far, so good.
When I send commands via UART, it works fine, and I can get a list of the files on the SD-Card or perform other access via FatFs without a problem.
The problem occurs, when I receive a command via USB-CDC. The parser works as expected, but FatFs claims FR_NO_FILESYSTEM (13) in f_opendir.
Also other FatFs commands fail with this error-code.
After one failed USB-command, commands via UART will also fail. It seems, as if the USB somehow crashes the initialized SD-Card-driver.
Any idea how I can resolve this behaviour? Or a starting point for debugging?
My USB-Implementation:
I'm using CubeMX, and therefore use the prescribed way to initialize the USB-CDC interface:
main() calls MX_USB_DEVICE_Init(void).
In usbd_conf.c I've got:
void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(pcdHandle->Instance==USB_OTG_FS)
{
/* USER CODE BEGIN USB_OTG_FS_MspInit 0 */
/* USER CODE END USB_OTG_FS_MspInit 0 */
/**USB_OTG_FS GPIO Configuration
PA11 ------> USB_OTG_FS_DM
PA12 ------> USB_OTG_FS_DP
*/
GPIO_InitStruct.Pin = OTG_FS_DM_Pin|OTG_FS_DP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(OTG_FS_IRQn, 7, 1);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
/* USER CODE END USB_OTG_FS_MspInit 1 */
}
}
and the receive-process is implemented in usbd_cdc_if.c as follows:
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
mRootObject->mUsbBuffer->fillBuffer(Buf, *Len);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
fillBuffer is implemented as follows (I use the same implementation for UART and USB transfer - with separate instances for the respective interfaces. mBuf is an instance-variable of type std::vector<char>):
void commBuf::fillBuffer(uint8_t *buf, size_t len)
{
// Check if last fill has timed out
if(SystemTime::getMS() - lastActionTime > timeout) {
mBuf.clear();
}
lastActionTime = SystemTime::getMS();
// Fill new content
mBuf.insert(mBuf.end(), buf, buf + len);
uint32_t done = 0;
while(!done) {
for(auto i = mBuf.end() - len, ee = mBuf.end(); i != ee; ++i) {
if(*i == '\n') {
newCommand = true;
myCommand = std::string((char*) &mBuf[0],i - mBuf.begin() + 1);
mBuf.erase(mBuf.begin(), mBuf.begin() + (i - mBuf.begin() + 1));
break;
}
}
done = 1;
}
}
I resolved the problem:
In usb_cdc_if.c the #define APP_RX_DATA_SIZE was set to 4 (for some unknown reason). As this is lower than the packet size, incoming packets of a larger size than 4 bytes were overwriting my memory.
It happened, that the following portion of my memory was the FATFS* FatFs[] pointer-list to the initialized FATFS-Filesystem structs.
So subsequently the address to this struct was overwritten, when a command of 5 or more bytes arrived.
Phew, that was a tough one.

How to read from and write to EEPROM suing SPI communication

I am using PIC32MX350F128L Microcontroller to read from and write to EEPROM(SST26VF032B) using SPI communication. SPI communication in this program is working, I have checked it by sending JEDEC code which is provided in the SST26VF032B datasheet. So when i send 0x9F i am getting 3 bytes of data as mentioned in the datasheet. When i run now i am sending a string of data to a specific address of eeprom and getting 0xff in return. I am erasing the eeprom before writing into it. So i think i am getting 0xff after erasing the eeprom. The writing, reading operations are not working. If i send a string of value or a BYTE i am getting 0xff in return. So can u guys please suggest me where i am going wrong. I am using UART for debugging purpose to read values recieved through spi communication. The complete code is below, i am using MPLAB X.
Best Regards
Sandesh
#include <xc.h>
#include <stdio.h>
#include <plib.h>
#include <p32xxxx.h>
/* Configuration Bits */
#pragma config FSRSSEL = PRIORITY_7 // Shadow Register Set Priority Select (SRS Priority 7)
#pragma config PMDL1WAY = ON // Peripheral Module Disable Configuration (Allow only one reconfiguration)
#pragma config IOL1WAY = ON // Peripheral Pin Select Configuration (Allow only one reconfiguration)
// DEVCFG2
#pragma config FPLLIDIV = DIV_2 // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_20 // PLL Multiplier (20x Multiplier)
#pragma config FPLLODIV = DIV_1 // System PLL Output Clock Divider (PLL Divide by 1)
// DEVCFG1
#pragma config FNOSC = PRIPLL // Oscillator Selection Bits (Primary Osc (XT,HS,EC))
#pragma config FSOSCEN = ON // Secondary Oscillator Enable (Enabled)
#pragma config IESO = ON // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = HS // Primary Oscillator Configuration (XT osc mode)
#pragma config OSCIOFNC = ON // CLKO Output Signal Active on the OSCO Pin (Enabled)
#pragma config FPBDIV = DIV_1 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/8)
#pragma config FCKSM = CSECME // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
#pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
#pragma config DEBUG = OFF // Background Debugger Enable (Debugger is Disabled)
#pragma config JTAGEN = OFF // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF // Program Flash Write Protect (Disable)
#pragma config BWP = OFF // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF // Code Protect (Protection Disabled)
/* MACRO DEFINITIONS */
/* Defining the Slave Select Pin */
#define SS LATDbits.LATD9
/* Defining the System Clock Frequency */
#define SYSCLK 40000000
/* Macro to get array size in bytes
* note that array size can't be found after passing pointer to a function */
#define LEN(x) (sizeof(x) / sizeof(x[0]))
/* SST26VF032B EEPROM instructions */
/* Write Enable */
#define WREN 0x06
/* Write Disable */
#define WRDI 0x04
/* Initialize Start of Write Sequence */
#define WRITE 0x02
/* Initialize Start of Read Sequence */
#define READ 0x03
/* Erase all sectors of Memory */
#define CE 0xc7
/* Read STATUS Register */
#define RDSR 0x05
/* Function Prototypes */
/* UART bit configuration */
void Bitconfig_uart(void);
/* SPI Initialization */
void SPI1_Init(void);
/* UART Initialization */
void Init_uart(void);
/* Send a Character Byte through UART */
void UART5PutChar(char Ch);
/* Function to Read and Write SPI1 buffer */
int SPI1_transfer( int b);
/* Function to check the Status of SPI */
void waitBusy();
/* Function to erase the contents in EEPROM */
void eraseEEPROM();
/* Function to Read data from EEPROM */
void readEEPROM( int address, char* loadArray, int loadArray_size);
/* Function to Write to EEPROM */
void writeEEPROM( int address, char* storeArray, int storeArray_size);
/* Global Variables Declaration */
/* Declare variables to check the functionality of EEPROM */
int i,j = 0;
char st = 0x9F;
char rec;
int x,y,z;
/*******************************************************************************
* Function Name: main()
********************************************************************************
* Summary:
* Initializes SPI
* Erase EEPROM
* Writes to EEPROM
* Read from EEPROM
*
* Parameters:
* None.
*
* Return:
* None.
*
*******************************************************************************/
int main()
{
int i;
/* Clock Setting */
SYSTEMConfigPerformance(SYSCLK);
/* UART bit configuration */
Bitconfig_uart();
/* Set the Controller OScillator Register bits */
//OSCCON = 0x00002200;
/* Initialize a String to Write to EEPROM and an array to Read back contents */
char writeData[] = "123456789ABCDEF";
/* Array to read 35 bytes of data */
char readData[15];
/* SPI Initialization */
SPI1_Init();
/* UART Initialization */
Init_uart();
/* Erase contents of EEPROM */
eraseEEPROM();
/* Write contents of writeData array to address 180 */
writeEEPROM( 0x1000, writeData, LEN(writeData));
/*
JEDEC Code (working) getting output as per datasheet (0x9F = 159)
SS=0;
SPI1_transfer(159);
x=SPI1_transfer(0);
UART5PutChar(x);
y=SPI1_transfer(0);
UART5PutChar(y);
z=SPI1_transfer(0);
UART5PutChar(z);
*/
while(1)
{
/* Read contents of EEPROM into readData array
* start at address 180 and read up to 180+length(readData) */
readEEPROM( 0x1000, readData, LEN(readData) );
}
} /* END main() */
/*******************************************************************************
* Function Name: SPI1_Init()
********************************************************************************
* Summary:
* SPI1 Initialization
*
* Parameters:
* None.
*
* Return:
* None.
*
*******************************************************************************/
void SPI1_Init(void)
{
/* Configure Peripheral Pin Select (PPS) for the SPI1 module
* Note: SS will be toggled manually in code
* SCK is hardwired to pin 55 */
/* Output Pin Selection */
RPE5R = 8;
SDI1R = 3;
/* RB4 (Slave Select 1) : output */
TRISDbits.TRISD9 = 0;
/* SPI configuration */
/* SPI1CON Register Configuration
* MSTEN: Master Mode Enable bit = 1 (Master)
* CKP (clock polarity control) = 0
* CKE (clock edge control) = 1
* ON: SPI Peripheral On bit
* 8-bit, Master Mode */
SPI1CON = 0x8120;
/* SPI1BRG Register Configuration */
SPI1BRG = 0x4D;
//REFOCONbits.ON = 1;
// REFOCONbits.DIVSWEN = 1;
}
/*******************************************************************************
* Function Name: SPI1_transfer()
********************************************************************************
* Summary:
* Write to and Read from SPI1 buffer
*
* Parameters:
* char b - Writes a Character to Buffer
*
* Return:
* Char - Returns the Character Read from EEPROM
*
*******************************************************************************/
int SPI1_transfer( int b)
{
/* write to buffer for TX */
SPI1BUF = b;
/* wait transfer complete */
while(!SPI1STATbits.SPIRBF);
/* read the received value */
return SPI1BUF;
} /* END SPI1_transfer() */
/*******************************************************************************
* Function Name: waitBusy()
********************************************************************************
* Summary:
* Checks if EEPROM is ready to be modified and waits if not ready
*
* Parameters:
* None.
*
* Return:
* None.
*
*******************************************************************************/
void waitBusy()
{
char status = 0;
do{
/* Select EEPROM */
SS = 0;
/* Read EEPROM status register */
SPI1_transfer(RDSR);
/* send dummy byte to receive incoming data */
status = SPI1_transfer(0);
/* Release EEPROM */
SS = 1;
}
/* write-in-progress while status<0> set to '1' */
while( status & 0x01);
} /* END waitBusy() */
/*******************************************************************************
* Function Name: readEEPROM()
********************************************************************************
* Summary:
* Reads data from EEPROM
*
* Parameters:
* Inputs: address - EEPROM address
* loadArray - array to load EEPROM data to
* loadArray_size - number of bytes of EEPROM data to load into array
*
* Return:
* None.
*
*******************************************************************************/
void readEEPROM( int address, char* loadArray, int loadArray_size)
{
int i;
/* Wait until EEPROM is not busy */
waitBusy();
/* Select EEPROM */
SS = 0;
/* Initiate Read */
SPI1_transfer( READ);
/* Address must be 16-bits but we're transferring it in two 8-bit sessions */
SPI1_transfer( address >> 16);
SPI1_transfer( address >> 8);
SPI1_transfer( address);
/* Request and store loadArray_size number of bytes into loadArray */
for( i=0 ; i<loadArray_size ; i++)
{
/* send dummy byte to read 1 byte */
loadArray[i] = SPI1_transfer( 0x00);
}
/* Release EEPROM */
SS = 1;
/* UART Test */
for(i=0;i<35;i++)
{
UART5PutChar(loadArray[i]);
for(j=0;j<20000;j++)
{}
}
} /* END readEEPROM() */
/*******************************************************************************
* Function Name: writeEEPROM()
********************************************************************************
* Summary:
* Write data to EEPROM
*
* Parameters:
* Inputs: address - EEPROM address
* storeArray - array of which contents are stored in EEPROM
* storeArray_size - number of bytes in array to store into EEPROM
*
* Return:
* None.
*
*******************************************************************************/
void writeEEPROM( int address, char* storeArray, int storeArray_size)
{
int i;
/* Wait until EEPROM is not busy */
waitBusy();
/* Select EEPROM */
SS = 0;
/* Send WRITE_ENABLE command */
SPI1_transfer( WREN);
/* Release EEPROM */
SS = 1;
/* Select EEPROM again after WREN cmd */
SS = 0;
/* Initiate Write */
SPI1_transfer( WRITE);
SPI1_transfer( address >> 16 );
SPI1_transfer( address >> 8 );
SPI1_transfer( address );
/* write 1 byte at a time from array */
/* MSB at lowest address (0 - first letter in string) */
for( i=0 ; i<storeArray_size; i++)
{
/* Initiate Write */
SPI1_transfer( WRITE);
SPI1_transfer( (address+i) >> 16 );
SPI1_transfer( (address+i) >> 8 );
SPI1_transfer( address+i );
SPI1_transfer( storeArray[i]);
}
/* Release EEPROM */
SS = 1;
} /* END writeEEPROM() */
/*******************************************************************************
* Function Name: eraseEEPROM()
********************************************************************************
* Summary:
* Erase entire contents of EEPROM
*
* Parameters:
* None
*
* Return:
* None.
*
*******************************************************************************/
void eraseEEPROM()
{
/* Wait until EEPROM is not busy */
waitBusy();
/* Select EEPROM */
SS = 0;
/* Send WRITE_ENABLE command */
SPI1_transfer( WREN);
/* Release EEPROM */
SS = 1;
/* Select EEPROM again after WREN cmd */
SS = 0;
/* send CHIP_ERASE command */
SPI1_transfer( CE);
/* Release EEPROM */
SS = 1;
} /* END eraseEEPROM() */
/*******************************************************************************
* Function Name: Init_uart()
********************************************g************************************
* Summary:
* Initialize UART4
*
* Parameters:
* None
*
* Return:
* None.
*
*******************************************************************************/
void Init_uart()
{
/* Enable UART */
U5MODEbits.ON = 1 ;
/* set baud rate(9600) */
U5BRG = 521;
/* Set U4STA Register for Enabling tx and rx */
U5STA=0x9400;
}
/*******************************************************************************
* Function Name: UART4PutChar(unsigned char Ch)
********************************************************************************
* Summary:
* Send data from controller to putty GUI
*
* Parameters:
* input
* unsigned char Ch - To Send a byte of data over UART
*
* Return:
* None.
*
*******************************************************************************/
void UART5PutChar(char Ch)
{
while(U5STAbits.UTXBF == 1);
U5TXREG=Ch;
}
/*******************************************************************************
* Function Name: Bitconfig_uart()
********************************************************************************
* Summary:
* UART Pin Configuration
*
* Parameters:
* None
*
* Return:
* None.
*
*******************************************************************************/
void Bitconfig_uart(void)
{
/* UART4 Initialization */
// OSCCON=0x00002200;
/* Set pins as digital */
ANSELBbits.ANSB2 = 0;
ANSELBbits.ANSB0 = 0;
/* Set UART Tx pin as Output */
TRISBbits.TRISB0 = 0; //in controler tx
TRISBbits.TRISB2 = 1; // in controller RX
/* Peripheral Pin select for UART4 */
U5RXR=0x07;
RPB0R=0x04;
}
I faced the same problem for 3 long days until I found that there's a 18bytes long register called Block Protection Register BPR.
You need to set its bits to 0, according to the memory area you want to write.
So I read the BPR (send command 0x72 followed by 18 byte read) and I found it was not at zero everywhere in my case.
Reading on page 41 of the datasheet you can see that after a power on the BPR register is set to 5555 FFFFFFFF FFFFFFFF, so it protects from write the whole memory.
So for testing purpose I tried to clears it completely, and there's a specific command (0x98) for that purpose, allowing you to write anywhere in the whole memory.
But be sure to write enable the memory (command 0x06) before sending the clear BPR command (command 0x98).
At this point if you read the BPR (command 0x72) you will read 00 at every of its 10 bytes. (And this means the whole memory is now writeable)
In this state the write now finally works for me.
(I sent WriteEnable - SectorErase - SectorRead - WriteEnable - SectorWrite - SectorRead and it now works!)
Hope it helps, the datasheet is very chaotic about that.
P.S.
Somewhere the datasheet says that BPR is 18 bytes long, it is wrong, the BPR is only 10 bytes long

can't capture ppp packets using winpcap sometimes

I am using winpcap on my Windows XP, wishing to capture ppp packets with my WCDMA card.
I have installed winpcap 4.1.3 and Microsoft Network Monitor 3.4.
I compile the example code basic_dump from the winpcap developer's pack. It can always list the ppp card:
1. \Device\NPF_GenericDialupAdapter (Adapter for generic dialup and VPN capture)
2. \Device\NPF_{04F9E6B9-214E-4FE5-892B-0419694392E1} (WAN (PPP/SLIP) Interface)
Sometimes it captures packets and prints timestamp and length as expected, sometimes it just prints nothing even when I am surfing the Internet.
Below is the code.
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "pcap.h"
/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
/* Retrieve the device list */
if(pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/* Open the device */
/* Open the adapter */
if ((adhandle= pcap_open_live(d->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
0, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
)) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d->description);
/* At this point, we don't need any more the device list. Free it */
pcap_freealldevs(alldevs);
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
pcap_close(adhandle);
return 0;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm *ltime;
char timestr[16];
time_t local_tv_sec;
/*
* unused parameters
*/
(VOID)(param);
(VOID)(pkt_data);
/* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}

Coding realtime clock for for ARM architecture based microcontroller

I need to write a program to implement real time clock for ARM architecture. example: LPC213x
It should display Hour Minute and Seconds. I have no idea about ARM so having trouble getting started.
My code below is not working
// ...
int main (void) {
int hour=0;
int min=0;
int sec;
init_serial(); /* Init UART */
Initialize();
CCR=0x11;
PCONP=0x1815BE;
ILR=0x1; // Clearing Interrupt
//printf("\nTime is %02d:%02x:%02d",hour,min,sec);
while (1) { /* Loop forever */
}
}
void Initialize()
{
VPBDIV=0x0;
//CCR=0x2;
//ILR=0x3;
HOUR=0x0;
SEC=0x0;
MIN=0x0;
ILR = 0x03;
CCR = (1<<4) | (1<<0);
VICVectAddr13 = (unsigned)read_rtc;
VICVectCntl13 |= 0x20 | VIC_RTC;
VICIntEnable |= (1 << VIC_RTC);
}
/* Interrupt Service Routine*/
__irq void read_rtc()
{
int hour=0;
int min=0;
int sec;
ILR=0x1; // Clearing Interrupt
hour=(CTIME0 & MASKHR)>>16;
min= (CTIME0 & MASKMIN)>>8;
sec=CTIME0 & MASKSEC;
printf("\nTime is %02d:%02x:%02d",hour,min,sec);
//VICVectAddr=0xff;
VICVectAddr = 0;
}
According to this board description for the LPC213x, it is delivered with an example program called "Real-Time Clock - Demonstrates how the real-time clock can be used". This also implies that the board features real-time clock hardware, which is going to make it a lot easier.
I suggest you read up on that program, to figure out how to talk to the RTC hardware. The next step would be to solve the display requirements. The two obvious choices are either 7-segment LED displays, or an LCD.
Both are well-known technologies about which loads have been written, follow the Wikipedia links to find out more.
This is all for the LPC2468. We have a setTime function too, but I don't want to do ALL the work for you. ;) We have custom register files for ease of access, but if you look at the LPC manual, it's obvious where they correlate. You just have to shift values into the right place, and do bitwise operations. For example:
#define RTC_HOUR (*(volatile RTC_HOUR_t *)(RTC_BASE_ADDR + (uint32_t)0x28))
Time struture:
typedef struct {
uint8_t seconds; /* Second value - [0,59] */
uint8_t minutes; /* Minute value - [0,59] */
uint8_t hour; /* Hour value - [0,23] */
uint8_t mDay; /* Day of the month value - [1,31] */
uint8_t month; /* Month value - [1,12] */
uint16_t year; /* Year value - [0,4095] */
uint8_t wDay; /* Day of week value - [0,6] */
uint16_t yDay; /* Day of year value - [1,365] */
} rtcTime_t;
RTC functions:
void rtc_ClockStart(void) {
/* Enable CLOCK into RTC */
scb_ClockStart(M_RTC);
RTC_CCR.B.CLKSRC = 1;
RTC_CCR.B.CLKEN = 1;
return;
}
void rtc_ClockStop(void) {
RTC_CCR.B.CLKEN = 0;
/* Disable CLOCK into RTC */
scb_ClockStop(M_RTC);
return;
}
void rtc_GetTime(rtcTime_t *p_localTime) {
/* Set RTC timer value */
p_localTime->seconds = RTC_SEC.R;
p_localTime->minutes = RTC_MIN.R;
p_localTime->hour = RTC_HOUR.R;
p_localTime->mDay = RTC_DOM.R;
p_localTime->wDay = RTC_DOW.R;
p_localTime->yDay = RTC_DOY.R;
p_localTime->month = RTC_MONTH.R;
p_localTime->year = RTC_YEAR.R;
}
System control block functions:
void scb_ClockStart(module_t module) {
PCONP.R |= (uint32_t)1 << module;
}
void scb_ClockStop(module_t module) {
PCONP.R &= ~((uint32_t)1 << module);
}
If you need information about ARM then this ARM System Developer's Guide: Designing and Optimizing System Software may help you.
We used to do some thing like this for ARM.
#include "LPC21xx.h"
void rtc()
{
*IODIR1 = 0x00FF0000;
// Set LED ports to output
*IOSET1 = 0x00020000;
*PREINT = 0x000001C8;
// Set RTC prescaler for 12.000Mhz Xtal
*PREFRAC = 0x000061C0;
*CCR = 0x01;
*SEC = 0;
*MIN = 0;
*HOUR= 0;
}
A real-time clock (RTC) is a computer clock (most often in the form of an integrated circuit) that keeps track of the current time. Although the term often refers to the devices in personal computers, servers and embedded systems, RTCs are present in almost any electronic device which needs to keep accurate time.
You May refer this two link, i am sure it will give you further understanding :-
1). ARM Cortex Programming using CMSIS:- http://www.firmcodes.com/cmsis/
2). RTC Programming with ARM7:- http://www.firmcodes.com/microcontrollers/arm/real-time-clock-of-arm7-lpc2148/