Embedded - SD card - SPI - C -Codevision AVR - Creating and writing a file in an SD card - embedded

I have an SD card (or SDHC card) connected to a microcontroller via SPI mode. I am using Chan’s FAT library. In this I used CodevisionAVR v2.05.3 example code from help. By using this I read a text document and opened the file using open existing.
However, when I created a new file or tried to write, I couldn't open the file (do f_open). Giving error ERROR: FR_INVALID_OBJECT.
How can I clear this issue?
And my code is:
/* ATmega128 I/O register definitions */
#include <io.h>
#if defined(_CHIP_ATMEGA32_)
#warning using ATMEGA32
#define TIMSK1 TIMSK
#define UCSR0A UCSRA
#define UCSR0B UCSRB
//#define UCSR0C UCSRC //this is commented out
#define UBRR0H UBRRH
#define UBRR0L UBRRL
#define TXEN0 TXEN
#endif
/* FAT on MMC/SD/SD HC card support */
#include <ff.h>
/* printf */
#include <stdio.h>
/* String functions */
#include <string.h>
#include <delay.h>
/* Timer1 overflow interrupt frequency [Hz] */
#define T1_OVF_FREQ 100
/* Timer1 clock prescaler value */
#define T1_PRESC 1024L
/* Timer1 initialization value after overflow */
#define T1_INIT (0x10000L-(_MCU_CLOCK_FREQUENCY_/(T1_PRESC*T1_OVF_FREQ)))
/* USART Baud rate */
#define BAUD_RATE 9600
#define BAUD_INIT (_MCU_CLOCK_FREQUENCY_/(BAUD_RATE*16L)-1)
/* Root directory path */
char path[] = "0:/fil.txt";
/* Text to be written to the file */
char text[]="I like CodeVisionAVR!";
/* 100 Hz timer interrupt generated by ATmega128 Timer1 overflow */
interrupt [TIM1_OVF] void timer_comp_isr(void)
{
/* Re-initialize Timer1 */
TCNT1H = T1_INIT >> 8;
TCNT1L = T1_INIT & 0xFF;
/* MMC/SD/SD HC card access low level timing function */
disk_timerproc();
}
/* Error message list */
flash char *flash error_msg[] = {
"", /* Not used */
"FR_DISK_ERR",
"FR_INT_ERR",
"FR_INT_ERR",
"FR_NOT_READY",
"FR_NO_FILE",
"FR_NO_PATH",
"FR_INVALID_NAME",
"FR_DENIED",
"FR_EXIST",
"FR_INVALID_OBJECT",
"FR_WRITE_PROTECTED",
"FR_INVALID_DRIVE",
"FR_NOT_ENABLED",
"FR_NO_FILESYSTEM",
"FR_MKFS_ABORTED",
"FR_TIMEOUT"
};
/* Display error message and stop */
void error(FRESULT res)
{
if ((res >= FR_DISK_ERR) && (res <= FR_TIMEOUT))
printf("ERROR: %p\r\n", error_msg[res]);
/* Stop here */
while (1);
}
void main(void)
{
/* FAT function result */
FRESULT res;
/* Will hold the information for logical drive 0: */
FATFS drive;
/* Will hold the file information */
FIL file;
/* Number of bytes written/read to the file */
unsigned int nbytes;
/* File read buffer */
char buffer[256];
/* Initialize Timer1 overflow interrupts in Mode 0 (Normal) */
TCCR1A = 0x00;
/* clkio/1024 */
TCCR1B = (1<<CS12)|(1<<CS10);
/* Timer overflow interrupts will occur with 100Hz frequency */
TCNT1H = T1_INIT >> 8;
TCNT1L = T1_INIT & 0xFF;
/* Enable Timer1 overflow interrupt */
TIMSK1 = 1 << TOIE1;
/* Initialize the USART0 TX, 8N1, Baud rate: 19200 */
UCSR0A = 0;
UCSR0B = 1 << TXEN0;
//UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
UBRR0H = BAUD_INIT >> 8;
UBRR0L = BAUD_INIT & 0xFF;
/* Globally enable interrupts */
#asm("sei")
PORTB.4 = 0;
delay_ms(1000);
printf("\n\nDirectory listing for root of logical drive 0:\r\n");
/* Mount logical drive 0: */
if ((res = f_mount(0, &drive)) == FR_OK)
printf("Logical drive 0: mounted OK\r\n");
else
/* An error occurred, display it and stop */
error(res);
printf("%s \r\n", path);
/* Open the file in read mode */
if ((res = f_open(&file, path, FA_READ)) == FR_OK)
printf("1_File %s opened OK\r\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Read and display the file's content.
make sure to leave space for a NULL terminator
in the buffer, so maximum sizeof(buffer)-1 bytes can be read */
if ((res=f_read(&file,buffer,sizeof(buffer)-1,&nbytes))==FR_OK)
{
printf("%u bytes read\r\n", nbytes);
/* NULL terminate the char string in the buffer */
buffer[nbytes+1]=NULL;
/* Display the buffer contents */
printf("Read text: \"%s\"\r\n", buffer);
}
else
/* An error occurred, display it and stop */
error(res);
/* Close the file */
if ((res = f_close(&file)) == FR_OK)
printf("1_File %s closed OK\r\n\n\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Create a new file in the root of drive 0:
and set write access mode */
if ((res = f_open(&file,path, FA_OPEN_EXISTING)) == FR_OK)
printf("File %s opened OK\r\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Close the file */
if ((res = f_close(&file)) == FR_OK)
printf("2_File %s closed OK\r\n\n\n", path);
else
/* An error occurred, display it and stop */
error(res);
if ((res = f_open(&file,path, FA_WRITE | FA_CREATE_ALWAYS)) == FR_OK)
printf("File %s created OK\r\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Write some text to the file,
without the NULL string terminator sizeof(data)-1 */
if ((res = f_write(&file, text, sizeof(text)-1,&nbytes)) == FR_OK)
printf("%u bytes written of %u\r\n", nbytes, sizeof(text)-1);
else
/* An error occurred, display it and stop */
error(res);
/* Close the file */
if ((res = f_close(&file)) == FR_OK)
printf("3_File %s closed OK\r\n\n\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Open the file in read mode */
if ((res = f_open(&file,path,FA_READ)) == FR_OK)
printf("1_File %s opened OK\r\n", path);
else
/* An error occurred, display it and stop */
error(res);
/* Read and display the file's content.
make sure to leave space for a NULL terminator
in the buffer, so maximum sizeof(buffer)-1 bytes can be read */
if ((res = f_read(&file, buffer, sizeof(buffer)-1, &nbytes)) == FR_OK)
{
printf("%u bytes read\r\n", nbytes);
/* NULL terminate the char string in the buffer */
buffer[nbytes+1] = NULL;
/* Display the buffer contents */
printf("Read text: \"%s\"\r\n", buffer);
}
else
/* An error occurred, display it and stop */
error(res);
/* Close the file */
if ((res = f_close(&file)) == FR_OK)
printf("4_File %s closed OK\r\n", path);
else
/* An error occurred, display it and stop */
error(res);
printf("done\r\n");
PORTB.4 = 1;
/* Stop here */
while (1);
}

From the documentation:
FR_INVALID_OBJECT
The file/directory object structure is invalid or a null pointer is given. All open objects of the logical drive are invalidated by the volume mount process.
Your file pointer is perhaps null?
Also to consider is that you have configured the library to actually support write operations. In ffconf.h you should have:
#define _FS_READONLY 0

Related

Input Capture mapping using PPS

I am trying to configure input capture module (IC1) on dsPIC33EP32MC204 to use it for duty cycle measurement. As input I would like to use RP35 pin. To test the correctness of the configuration I set up an experiment: I connected a pulse generator with 1Hz PWM pulses and set up the input capture to capture every rising edge. I reckoned that these rising edges will trigger the input capture interrupt and each call of the interrupt will cause the LED to blink. Unfortunatelly it is not working. I would be grateful if someone could tell me where is the problem. The code:
void Init_InputCapture(void)
{
IC1CON1bits.ICSIDL = 0;
IC1CON1bits.ICTSEL = 0b111; // Peripheral clock (FP) is the clock source of the ICx
IC1CON1bits.ICI = 0b00; //
IC1CON1bits.ICM = 0b011; //Capture mode every edge rising
IC1CON2bits.ICTRIG = 0; // = Input source used to trigger the input capture timer (Trigger mode)
IC1CON2bits.SYNCSEL = 0b00000; //IC1 module synchronizes or triggers ICx
IC1CON2bits.IC32 = 0; // 16 bit mode only
// Enable Capture Interrupt And Timer2
IPC0bits.IC1IP = 1; // Setup IC1 interrupt priority level
IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
IEC0bits.IC1IE = 1; // Enable IC1 interrupt
}
The interrupt:
void __attribute__((__interrupt__, no_auto_psv)) _IC1Interrupt(void)
{
LATBbits.LATB9 = ~LATBbits.LATB9;
IFS0bits.IC1IF = 0;
}
And the related code from the main():
__builtin_write_OSCCONL(OSCCON & ~(1<<6));
RPINR7 = 0x23; ; // IC1 mapped to RP35
__builtin_write_OSCCONL(OSCCON | (1<<6));
During the setup I followed the instuctions from the family reference manual.
The code you have posted could be more complete. For dsPIC controllers it is essential to show exactly how all of the configuration bits are set and how the system clock is initialized.
This is your code corrected with the minimum required setup code:
/*
* file: main.c
* target: dsPIC33EP32MC204
* IDE: MPLABX v4.05
* Compiler: XC16 v1.35
*
* Description:
* Use Input Capture 1 module to catch a 1Hz pulse on GPIO RP35 and toggle LED on RB9.
*
*/
#pragma config ICS = PGD2 // ICD Communication Channel Select bits (Communicate on PGEC2 and PGED2)
#pragma config JTAGEN = OFF // JTAG Enable bit (JTAG is disabled)
#pragma config ALTI2C1 = OFF // Alternate I2C1 pins (I2C1 mapped to SDA1/SCL1 pins)
#pragma config ALTI2C2 = OFF // Alternate I2C2 pins (I2C2 mapped to SDA2/SCL2 pins)
#pragma config WDTWIN = WIN25 // Watchdog Window Select bits (WDT Window is 25% of WDT period)
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128 // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON // PLL Lock Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)
#pragma config POSCMD = NONE // Primary Oscillator Mode Select bits (Primary Oscillator disabled)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF // Peripheral pin select configuration (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)
#pragma config FNOSC = FRC // Oscillator Source Selection (Internal Fast RC (FRC))
#pragma config PWMLOCK = ON // PWM Lock Enable bit (Certain PWM registers may only be written after key sequence)
#pragma config IESO = OFF // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)
#pragma config GWRP = OFF // General Segment Write-Protect bit (General Segment may be written)
#pragma config GCP = OFF // General Segment Code-Protect bit (General Segment Code protect is Disabled)
#include <xc.h>
/* Setup the clock to run at about 60 MIPS */
#define FOSC (7372800L) /* nominal fast RC frequency */
#define PLL_N1 (2L) /* PLLPRE CLKDIV<4:0> range 2 to 33 */
#define PLL_M (65L) /* PLLDIV PLLFBD<8:0> range 2 to 513 */
#define PLL_N2 (2L) /* PLLPOST CLKDIV<7:6> range 2, 4 or 8 */
#define FSYS (FOSC*PLL_M/(PLL_N1*PLL_N2))
#define FCYC (FSYS/2L)
/*
* Global constant data
*/
const unsigned long gInstructionCyclesPerSecond = FCYC;
/*
* Initialize this PIC
*/
void PIC_Init( void )
{
unsigned int ClockSwitchTimeout;
/*
** Disable all interrupt sources
*/
__builtin_disi(0x3FFF); /* disable interrupts for 16383 cycles */
IEC0 = 0;
IEC1 = 0;
IEC2 = 0;
IEC3 = 0;
IEC4 = 0;
IEC5 = 0;
IEC6 = 0;
IEC8 = 0;
IEC9 = 0;
__builtin_disi(0x0000); /* enable interrupts */
CLKDIV = 0; /* Disable DOZE mode */
if(!OSCCONbits.CLKLOCK) /* if primary oscillator switching is unlocked */
{
/* Select primary oscillator as FRC */
__builtin_write_OSCCONH(0b000);
/* Request switch primary to new selection */
__builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));
/* wait, with timeout, for clock switch to complete */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);
/* Configure PLL prescaler, PLL postscaler, PLL divisor */
PLLFBD=PLL_M-2; /* M=65 */
#if PLL_N2==2
CLKDIVbits.PLLPOST=0; /* N2=2 */
#elif PLL_N2==4
CLKDIVbits.PLLPOST=1; /* N2=4 */
#elif PLL_N2==8
CLKDIVbits.PLLPOST=3; /* N2=8 */
#else
#error invalid PLL_N2 paramenter
#endif
CLKDIVbits.PLLPRE=PLL_N1-2; /* N1=2 */
/* Select primary oscillator as FRCPLL */
__builtin_write_OSCCONH(0b001);
/* Request switch primary to new selection */
__builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));
/* wait, with timeout, for clock switch to complete */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);
/* wait, with timeout, for the PLL to lock */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && !OSCCONbits.LOCK;);
/* at this point the system oscillator should be 119.808MHz */
}
/* make all inputs digital I/O */
ANSELA = 0x00;
ANSELB = 0x00;
ANSELC = 0x00;
/* Unlock PPS Registers */
__builtin_write_OSCCONL(OSCCON & ~(_OSCCON_IOLOCK_MASK));
/* map all PPS pins */
RPINR7bits.IC1R = 35; // Select RP35 (RB3/PGED1) as input for IC1
/* Lock PPS Registers */
__builtin_write_OSCCONL(OSCCON | (_OSCCON_IOLOCK_MASK));
}
/*
* Initialize Input Capture 1
*/
void Init_InputCapture( void )
{
IC1CON1bits.ICSIDL = 0;
IC1CON1bits.ICTSEL = 0b111; // Peripheral clock (FP) is the clock source of the ICx
IC1CON1bits.ICI = 0b00; //
IC1CON1bits.ICM = 0b011; //Capture mode every edge rising
IC1CON2bits.ICTRIG = 0; // = Input source used to trigger the input capture timer (Trigger mode)
IC1CON2bits.SYNCSEL = 0b00000; //IC1 module synchronizes or triggers ICx
IC1CON2bits.IC32 = 0; // 16 bit mode only
// Enable Capture Interrupt And Timer2
IPC0bits.IC1IP = 4; // Setup IC1 interrupt priority level
IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
IEC0bits.IC1IE = 1; // Enable IC1 interrupt
}
/*
* Interrupt Service Routine for IC1
*/
void __attribute__((__interrupt__, no_auto_psv)) _IC1Interrupt(void)
{
IFS0bits.IC1IF = 0;
LATBbits.LATB9 ^= 1; // toggle LED
}
/*
* Main process loop
*/
int main( void )
{
PIC_Init();
TRISBbits.TRISB9 = 0; // make RB9 an output
LATBbits.LATB9 = 0; // turn off LED
Init_InputCapture();
for(;;)
{
/* process loop */
}
return 0;
}

LPC824 microcontroller ADC demo HardFault problem

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.

Delayed uart command execution

I'm writing a small embedded program, where I send some commands over uart to the atmega328p chip. The commands start with the character $ and end with the character # (so I know when to perform the parsing). Upon receiving the command I parse it and turn the device on (COMMAND:TURN_ON_I1) or off (COMMAND:TURN_OFF_I1). The application currently looks like this:
// ------- Defines -------- //
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include "pinDefines.h"
#include "USART.h"
#define RECEIVE_BUFFER_SIZE 100
// Control output value
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
// Set pin mode (input or output)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
// The DDRD port contains only two pins:
#define REL_BTN_SIM_2 PD6 // PD6 = REL_BTN_SIM_2
void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}
void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}
int main(void) {
//$COMMAND:TURN_ON_I1#
//$COMMAND:TURN_OFF_I1#
char s[RECEIVE_BUFFER_SIZE];
char readSerialCharacter;
// -------- Inits --------- //
DDRB = 0b00000111;
DDRC = 0b00001000;
DDRD = 0b11000000;
initUSART();
// ------ Event loop ------ //
while (1) {
printString("Waiting for the start of string (char $).\r\n");
do { } while ( receiveByte() != '$'); // Wait for start of string.
// Fill the array until the end of transmission is received
int i=0;
do {
// If nearing end of buffer, don't fill the buffer and exit the loop
if(i<RECEIVE_BUFFER_SIZE-1){
readSerialCharacter = receiveByte();
s[i++] = readSerialCharacter;
}else
break;
} while (readSerialCharacter != '#'); // Wait for end of string.
s[i] ='\0'; // Terminate the string
printString("The whole received command:\r\n");
printString(s);
printString("\r\n");
// Other commands (temperature, relay control)
// REL_BTN_SIM_2
else if(strstr(s, "COMMAND:TURN_ON_I1") != NULL)
{
printString("Will set I1 on!");
output_high(PORTD, REL_BTN_SIM_2);
}
else if(strstr(s, "COMMAND:TURN_OFF_I1") != NULL)
{
printString("Will set I1 off!");
output_low(PORTD, REL_BTN_SIM_2);
}
else
printString("Unknown command.\r\n");
// Clear the buffer
memset(s,'\0', sizeof(s));
}
/* End event loop */
return (0);
}
I noticed that after I send a command around seven or eight times (or more), the serial communication is interrupted or that the command is executed with a delay. I can also see, that the debug strings "Will set I1 off!", "Will set I1 on!" are printed, but the state of the outputs are not changed (or are changed with a delay of a couple of seconds).
I was wondering if someone would know, what I'm doing wrong?
Thanks.
You have a nice definition of set_output(), but you are not using it. So I suspect that you never enabled the output driver. By setting the port register, you just enable the weak pull-up. Maybe that is not strong enough to switch on your relay driver fast. Do you have a capacitor in that driver circuit?

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);
}