I am not an expert c programmers and in the c code I m getting these kinds of errors. I got many and tried to sort them out but can not solve these. The code is as follows:
/*
* EEPROM.c
* interfacing microchip 24aa64f IC with atmel sam4e
*/
#include <asf.h>
#include "EEPROM_I2C.h"
#define DEVICE_ADDRESS 0x50 // 7-bit device identifier 0101000, (refer datasheet)
//#define EEPROM_NAME 24AA6F
#define I2C_FAST_MODE_SPEED 400000//TWI_BUS_CLOCK 400KHz
#define TWI_CLK_DIVIDER 2
#define TWI_CLK_DIV_MIN 7
#define TWI_CLK_CALC_ARGU 4
#define TWI_CLK_DIV_MAX 0xFF
/*************************** Main function ******************************/
int eeprom_main( void )
{
struct micro24 ptMicro24 ;
typedef struct twi_options twi_options_t;
typedef struct Twi_registers Twi;
char TxBuffer[128] ;
char RxBuffer[128] ;
int BufferIndex;
unsigned int PageCount;
unsigned int error = 0 ;
unsigned int i;
ptMicro24.PageSize = 32;
ptMicro24.NumOfPage = 128;
ptMicro24.EepromSize = 128*32;
ptMicro24.SlaveAddress = DEVICE_ADDRESS;
ptMicro24.EepromName = 64;
/***************************** CLOCK SETTINGS TO GET 400KHz **********************
* Set the I2C bus speed in conjunction with the clock frequency.
* param p_twi Pointer to a TWI instance.
* return value PASS\Fail New speed setting is accepted\rejected
**********************************************************************************/
uint32_t twi_set_speed(struct Twi_registers *Twi, uint32_t ul_speed, uint32_t ul_mck)
//uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
{
uint32_t ckdiv = 0; //clock divider is used to increase both TWCK high and low periods (16-18)
uint32_t c_lh_div; //CHDIV (0-7) and CLDIV (8-15)
if (ul_speed > I2C_FAST_MODE_SPEED) { //ul_speed is the desired I2C bus speed
return FAIL;
}
c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU; //ul_mck main clock of the device
/* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN))
{
ckdiv++; // Increase clock divider
c_lh_div /= TWI_CLK_DIVIDER; //Divide cldiv value
}
/* set clock waveform generator register */
Twi->TWI_CWGR =
TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
TWI_CWGR_CKDIV(ckdiv);
return PASS;
}
/************************************ Initialize TWI master mode ************************
* Set the control register TWI_CR by MSEN and SVDIS
* param p_opt Options for initializing the TWI module
* return TWI_SUCCESS if initialization is complete
* twi_options... structure contains clock speed, master clock, chip and smbus
*****************************************************************************************/
uint32_t twi_master_start(struct Twi_registers *Twi, struct twi_options_t *twi_options_t)
//uint32_t twi_master_start(Twi *p_twi, const twi_options_t *p_opt)
{
uint32_t status = TWI_SUCCESS; // status success return code is 0
// Enable master mode and disable slave mode in TWI_CR
Twi -> TWI_CR_START = TWI_CR_START;
Twi->TWI_CR_MSEN = TWI_CR_MSEN; // Set Master Enable bit
Twi->TWI_CR_SVDIS = TWI_CR_SVDIS; // Set Slave Disable bit
/* Select the speed */
//new//if (twi_set_speed(Twi->TWI_SR, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//if (twi_set_speed(Twi, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//{
//status = TWI_INVALID_ARGUMENT; /* The desired speed setting is rejected */
//}
if (twi_options_t->smbus == 0)
{
Twi->TWI_CR_QUICK == 0;
status = TWI_INVALID_ARGUMENT;
}
else
if (twi_options_t->smbus == 1)
{
Twi->TWI_CR_QUICK == 1;
status = TWI_SUCCESS;
}
return status;
}
/***************************** WriteByte Function ********************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
***********************************************************************************/
void WriteByte (struct micro24 *ptMicro24, char Data2Write,
unsigned int Address)
//Data2Write is the data to be written n the eeprom
//struct <micro24 *ptMicro24> : Structure of Microchip 24AA Two-wire Eeprom
//unsigned int Address>: Address where to write
{
unsigned int WordAddress;
unsigned int SlaveAddress;
unsigned char p0=0;
TWI_CR_START ==1;
if (ptMicro24->EepromName == 64 )
{
if ( Address > 0xFFFF)
{
p0 = 1;
/* Mask the 17th bit to get the 16th LSB */
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
TWI_CR_STOP ==1;
//TWI_WriteSingleIadr(TWI_IADR_IADR,SlaveAddress, WordAddress,
// TWI_MMR_IADRSZ_2_BYTE, &Data2Write); // declared as extern
// to write to internal address, utilizing internal address and master mode register
//}
/******************** Increase Speed Function *****************************
* TWI is accessed without calling TWI functions
/***************************************************************************/
int NumOfBytes, Count;
int status;
uint32_t Buffer;
/* Enable Master Mode of the TWI */
TWI_CR_MSEN == 1;
// Twi.TWI_CR_MSEN ==1;
//TWI_CR->TWI_CR_MSEN = TWI_CR_MSEN ;
/* Set the TWI Master Mode Register */
Twi->TWI_MMR = (SlaveAddress & (~TWI_MMR_MREAD) | (TWI_MMR_IADRSZ_2_BYTE));
/* Set the internal address to access the wanted page */
Twi -> TWI_IADR = WordAddress ;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
/* Send the buffer to the page */
for (Count=0; Count < NumOfBytes ;Count++ )
{
Twi ->TWI_THR_TXDATA = Buffer++;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
}
/* Wait for the Transmit complete is set */
status = TWI_SR_TXCOMP;
while (!(status & TWI_SR_TXCOMP))
status = TWI_SR_TXCOMP;
// add some wait function according to datasheet before sending the next data
// e.g: 10ms
// e.g: WaitMiliSecond (10);
}
/****************************** ReadByte Function **************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
****************************************************************************/
char ReadByte (struct micro24 *ptMicro24,
unsigned int Address) //int Address to read
{
unsigned int WordAddress;
unsigned int SlaveAddress;
char Data2Read ;
unsigned char p0=0;
TWI_CR_START == 1;
//p_twi -> TWI_CR_START = TWI_CR_START;
if (ptMicro24->EepromName == 64)
{
if ( Address > 0xFFFF) {
p0 = 1;
// Mask the 17th bit to get the 16th LSB
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
//TWI_ReadSingleIadr(TWI_IADR_IADR,SlaveAddress,WordAddress,
// TWI_MMR_IADRSZ_2_BYTE,&Data2Read);
// declared as extern
// to write to internal address, utilizing internal address and master mode register
return (Data2Read);
}
}
errors are:
(24,19): error: storage size of 'ptMicro24' isn't known
67,5): error: dereferencing pointer to incomplete type
Twi->TWI_CWGR =
error: expected identifier before '(' token
#define TWI_CR_START (0x1u << 0) /**< \brief (TWI_CR) Send a START Condition */
error: expected identifier before '(' token
#define TWI_CR_MSEN (0x1u << 2) /**< \brief (TWI_CR) TWI Master Mode Enabled */
error: expected identifier before '(' token
#define TWI_CR_SVDIS (0x1u << 5) /**< \brief (TWI_CR) TWI Slave Mode Disabled */
error: dereferencing pointer to incomplete type
if (twi_options_t->smbus == 0)
It seems missing the declaration of struct micro24, this may be the cause of first error: error: storage size of 'ptMicro24' isn't known.
The same for declaration of Twi_registers, that is causing other errors.
Either you forgot to declare these structs or to include an header file declaring them.
Related
I'm working on an AVR to learn it. my code is working properly. mean it gave me the output same as I want but I want to modify the code. I made 4 functions to send the data to the slave. like as it's in the code I want to send 61,62,63,64. but for these, I make four functions. Now I want to modify it as all the data send to the salve by one function. so my line of code will be reduced. second I want that once the 61 sends to the salve it prints something like datatransfered and once the dataexchange it's display **exchanged**. I tried to make the array and take numbers one by one but was unlucky.
#include <xc.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
void SPI0_init(void);
void LTCSelect(void);
void LTCDeselect(void);
uint8_t SPI0_exchangeData(uint8_t data);
uint8_t SPI1_exchangeData(uint8_t data1);
uint8_t SPI2_exchangeData(uint8_t data2);
uint8_t SPI3_exchangeData(uint8_t data3);
void SPI0_init(void){
PORTA.DIR |= PIN4_bm; /* Set MOSI pin direction to output (output to LTC2983) */
PORTA.DIR &= ~PIN5_bm; /* Set MISO pin direction to input (input form LTC2983) */
PORTA.DIR |= PIN6_bm; /* Set SCK pin direction to output (output to LTC2983) */
PORTA.DIR |= PIN7_bm; /* Set CS pin direction to output (output to LTC2983) */
SPI0.CTRLA = SPI_CLK2X_bm /* Enable double-speed */
| SPI_DORD_bm /* LSB is transmitted first */
| SPI_ENABLE_bm /* Enable module */
| SPI_MASTER_bm /* SPI module in Master mode */
| SPI_PRESC_DIV16_gc; /* System Clock divided by 16 */}
uint8_t SPI0_exchangeData(uint8_t data){
SPI0.DATA = data;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI1_exchangeData(uint8_t data1)
{
SPI0.DATA = data1;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI2_exchangeData(uint8_t data2){
SPI0.DATA = data2;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
uint8_t SPI3_exchangeData(uint8_t data3){
SPI0.DATA = data3;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;}
void LTCSelect(void){
PORTA.OUT &= ~PIN7_bm; // Set SS pin value to LOW}
void LTCDeselect(void){
PORTA.OUT |= PIN7_bm; // Set SS pin value to HIGH}
int main(void){
uint8_t data = 61;
uint8_t data1 = 62;
uint8_t data2 = 63;
uint8_t data3 = 64;
SPI0_init();
while(1){
LTCSelect();
SPI0_exchangeData(data);
SPI1_exchangeData(data1);
SPI2_exchangeData(data2);
SPI3_exchangeData(data3);
LTCDeselect();
}}
Just use the first function. The others are just a copy, are the same and unnecessary.
uint8_t SPI0_exchangeData(uint8_t data){
SPI0.DATA = data;
while (!(SPI0.INTFLAGS & SPI_IF_bm)) /* waits until data is exchanged*/
{
}
return SPI0.DATA;
}
and in your main loop call the same function to send all your data:
int main(void){
uint8_t data = 61;
uint8_t data1 = 62;
uint8_t data2 = 63;
uint8_t data3 = 64;
SPI0_init();
while(1){
LTCSelect();
SPI0_exchangeData(data);
SPI0_exchangeData(data1);
SPI0_exchangeData(data2);
SPI0_exchangeData(data3);
LTCDeselect();
}
}
There you shuld have your numbers respectively in your slave device.
Update for sending array
/**
* Sends an uint8_t array to SPI0
*
* Here we send an array of uint8_t (aka unsigned char) to SPI0 one by one.
* using the length parameter and an index variable.
*
* #param data a data array to send to SPI0.
* #param length the length of the given array.
* #returns nothing, but you can return any util info if you wish
*/
void sendArray(uint8_t data[], uint8_t length) {
for(uint8_t i = 0; i < length; i++) {
SPI0_exchangeData(data[i]);
}
}
// Suppose we have an array named buffer
uint8_t buffer[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
// Some where in the main loop we want to send it to the SPI0
int main(void) {
//...
while(1) {
//...
// We pass the array and its length in this way
sendArray(buffer, sizeof(buffer));
}
return 0;
}
Note that the array is defined and assigned statically. In real cases the arrays mostly used with a statically allocated memory, say 64 bytes i.e. uint8_t buffer[64];, but this does not mean that it will contain data in full capacity. Hence when the data is written to an array must be counted and stored in a variable to know the actual length of that array when needed.
I am a beginner with PIC microcontrollers and trying to learn through tutorials and simultaneously implement a project for which I need to program a PIC microcontroller. I have tried 3 different programs for UART transmission found on various tutorials and I am still having the same issue.
When I try to transmit a string, say "abcd", I only get adadadad.... on repeat. What might be the issue? I have checked the baud rates and it is correct. I have tried introducing delay but it doesnot help. Would greatly appreciate any suggestions. The UART transmission function is part of a frequency counter program that counts the frequency when it receives an interrupt and displays it on LCD. The value displayed on LCD is also to be transmitted via UART, but first I am trying to make it work for a random string "abcd". I am using proteus for simulations. Currently using the following functions for transmitting data string:
void UART_send_char(char bt)
{
while(!TXIF); // hold the program till TX buffer is free
TXREG = bt; //Load the transmitter buffer with the received value
}
void UART_send_string(char* st_pt)
{
while(*st_pt) //if there is a char
UART_send_char(*st_pt++); //process it as a byte data
}
Following is my main function:
void main() {
char op[12]; // Display string for ascii converted long.
char opdb[12]; // double buffer to stop flicker.
unsigned long freq = 0; // display frequency value to use.
unsigned short blinkc=0; // blink counter
int i,n,num;
unsigned char letter;
unsigned char test[]="abcd";
init_ports();
init_interrupts();
Lcd_Init ();
Lcd_Cmd ( _LCD_CLEAR );
Lcd_Cmd ( _LCD_CURSOR_OFF );
start_timer_count();
for(;;) {
if (update_LCD) {
INTCON.GIE = 0; // Disable All interrupts.
INTCON.PEIE = 0; // Disable All Extended interrupts.
freq = (st_TMR1L+(st_TMR1H<<8)+(st_TMR1_ovfl<<16));//*1000;
ltoa(freq, op, 10);
n=ltoa(freq, opdb, 10); // Build string in non display buffer
memcpy(op,opdb,n); // Copy digits
memset(&op[n],' ',12-n); // Blank the rest.
LCD_Out(1,1,"FREQ:");
LCD_Out(1,7,op);
UART_send_string("abcd"); //<-----------TRANSMISSION FUNCTION CALLED HERE
update_LCD=0;
TMR1_counter=0;
TMR0_counter=0;
start_timer_count();
}
if (toggle_LED) { // Also check for signal presence at TMR1.
blinkc=~blinkc;
if (blinkc==0) { setBit(PORTD,0); } else { resBit(PORTD,0); }
toggle_LED=0;
if (freq==0) {
for ( i=0;i<12;i++) { op[i]=' ';}
LCD_Out(1,7,op);
}
}
}
}
This is a complete, builds with MPLABX and XC8, application to show the PIC16F877A asynchronous UART working with the Microchip simulation tool:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F877A
* Compiler: XC8 v2.32
* IDE: MPLABX v5.50
*
* Created on July 21, 2021, 1:29 PM
*
* PIC16F877A
* +----------:_:----------+
* VPP -> 1 : MCLR/VPP PGD/RB7 : 40 <> PGD
* <> 2 : RA0/AN0 PGC/RB6 : 39 <> PGC
* <> 3 : RA1/AN1 RB5 : 38 <>
* <> 4 : RA2/AN2 RB4 : 37 <>
* <> 5 : RA3/AN3 RB3 : 36 <>
* <> 6 : RA4 RB2 : 35 <>
* <> 7 : RA5/AN4 RB1 : 34 <>
* <> 8 : RE0/AN5 RB0 : 33 <>
* <> 9 : RE1/AN6 VDD : 32 <- 5v0
* <> 10 : RE2/AN7 VSS : 31 <- GND
* 5v0 -> 11 : VDD RD7 : 30 ->
* GND -> 12 : VSS RD6 : 29 ->
* 20.000MHz -> 13 : OSC1 RD5 : 28 ->
* 20.000MHz <- 14 : OSC2 RD4 : 27 ->
* <> 15 : RC0/SOSCO RX/DT/RC7 : 26 <>
* <> 16 : RC1/SOSCI TX/CK/RC6 : 25 <>
* <> 17 : RC2/CCP1 RC5 : 24 <>
* <> 18 : RC3/SCL SDA/RC4 : 23 <>
* <> 19 : RD0 RD3 : 22 <>
* <> 20 : RD1 RD2 : 21 <>
* +-----------------------:
* DIP-40
*
* Description:
*
* Unit test for the UART transmit output implementation.
*
* Test runs using the MPLABX v5.50 simulator.
*
* Read the Microchip documentation about how to setup the simulator to show UART output.
*
*/
#pragma config FOSC = HS /* Oscillator Selection bits (HS oscillator) */
#pragma config WDTE = OFF /* Watchdog Timer Enable bit (WDT disabled) */
#pragma config PWRTE = OFF /* Power-up Timer Enable bit (PWRT disabled) */
#pragma config BOREN = OFF /* Brown-out Reset Enable bit (BOR disabled) */
#pragma config LVP = OFF /* Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) */
#pragma config CPD = OFF /* Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) */
#pragma config WRT = OFF /* Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) */
#pragma config CP = OFF /* Flash Program Memory Code Protection bit (Code protection off) */
/*
* Include defines for target specific Special Function Registers
*/
#include <xc.h>
/*
* Tell XC8 compiler what frequency this code sets for system oscillator
*/
#define _XTAL_FREQ 20000000UL
/*
* function to convert unsigned long to ASCII string
*/
void ultoa(void * str, unsigned long data, unsigned char radix)
{
char buffer[32];
char * outstr = 0;
unsigned char index;
unsigned char temp;
outstr = (char *)str;
if(outstr)
{
if((radix > 1) && (radix <= 16))
{
index = 0;
do
{
temp = data % radix;
data = data / radix;
temp = temp + '0';
if (temp > '9') temp = temp + ('A'-'9')-1;
buffer[index++] = temp;
} while (data);
do
{
*outstr++ = buffer[--index];
} while(index);
*outstr = 0;
}
}
}
/*
* Initialize UART
*/
void UART_Init(void)
{
/* Disable UART interrupts */
PIE1bits.TXIE = 0;
PIE1bits.RCIE = 0;
/* Turn off USART module */
RCSTA = 0;
TXSTA = 0;
SPBRG = (_XTAL_FREQ/(16UL * 9600UL) - 1);
TXSTAbits.BRGH = 1;
RCSTAbits.CREN = 1; /* Enable continuous receive */
TXSTAbits.TXEN = 1; /* Enables Transmission */
RCSTAbits.SPEN = 1; /* Enables Serial Port */
/*
* Flush UART receive buffer
*/
RCREG;
RCREG;
RCREG;
}
/*
* Send a character to serial interface
*/
void UART_Write(unsigned char data) {
while(!TRMT); /* Wait for buffer to be empty */
TXREG = data;
}
/*
* Send a string of characters to serial interface
*/
void UART_WriteString(char *pBuffer) {
if (pBuffer)
{
while(*pBuffer)
{
UART_Write(*pBuffer++);
}
}
}
/*
* Test if character is available from serial interface
*/
unsigned char UART_Data_Ready( void )
{
return (RCIF!=0?1:0);
}
/*
* Read a character from serial interface
* Returns a zero if successful.
* Returns non-zero on framing error or overrun error.
*/
unsigned char UART_Read(void *data)
{
unsigned char Result;
char * buffer = (char *)data;
Result = 0;
if (PIR1bits.RCIF)
{
unsigned char rxerr = 0;
if (RCSTAbits.OERR) {
rxerr = 1;
RCSTAbits.CREN = 0; /* reset receiver */
RCSTAbits.CREN = 1;
RCREG;
RCREG;
RCREG;
}
if (RCSTAbits.FERR) {
rxerr = 1;
RCREG; /* Discard character with framing error */
}
if (!rxerr) { /* No error detected during reception */
if(buffer) *buffer = RCREG;
Result = 1;
}
}
return Result;
}
/*
* Initialize this PIC
*/
void PIC_Init( void )
{
/* Disable all interrupt sources */
INTCON = 0;
PIE1 = 0;
PIE2 = 0;
/*
* Pull-ups off, INT edge low to high, WDT prescale 1:1
* TMR0 clock edge low to high, TMR0 clock = _XTAL_FREQ/4, TMR0 prescale 1:16
* TIMER0 will assert the overflow flag every 256*16 (4096)
* instruction cycles, with a 20MHz oscillator this is 0.8192 milliseconds.
*/
OPTION_REG = 0b11000011;
/* Make all GPIO pins digital */
CMCON = 0x07;
ADCON1 = 0x06;
}
/*
* Main application
*/
void main(void)
{
char output[40];
unsigned long Count;
/*
* Initialize application
*/
PIC_Init();
UART_Init();
UART_WriteString("PIC16F877A UART test build on " __DATE__ " at " __TIME__ "\r\n");
Count = 0;
/*
* Application process loop
*/
for(;;)
{
ultoa(output,Count,10);
UART_WriteString("Count: ");
UART_WriteString(output);
UART_WriteString("\r\n");
Count++;
}
/*
* Keep XC8 from whining about functions not being called
*/
UART_Data_Ready();
UART_Read(0);
}
I would expect this to work with your Proteus environment too.
It's on you to port this code to your project.
I'm trying to write a code for ADC DMA. In my perspective, I've initiated ADC correctly. But it doesn't work and it doesn't interrupt. What am I missing? I initiated ADC and Interrupt and I am willing to access data on the interrupt.
Here is my code:
void __irq ISR_adc(void)
{
volatile AT91PS_ADC pADC = AT91C_BASE_ADC;
unsigned int AdcStatus = AT91C_BASE_ADC->ADC_SR;
unsigned short* ADC_Ptr;
unsigned short* ADC_Ptr_Next;
printf("ADC is: %d\n",Buffer1[0]);
if(((AdcStatus & AT91C_ADC_RXBUFF) == AT91C_ADC_RXBUFF) &&
((AdcStatus & AT91C_ADC_ENDRX) == AT91C_ADC_ENDRX))
{//Both bit set when get the end of next buffer
pADC->ADC_RPR = (unsigned long) Buffer1; // Receive Pointer Register
pADC->ADC_RCR = AD_DATA_BUFFER_SIZE; // Receive Counter Register
pADC->ADC_RNPR = (unsigned long)0; // Receive Next Pointer Register
pADC->ADC_RNCR = 0 ; // Receive Next Counter Registe
}
else if((AdcStatus & AT91C_ADC_ENDRX) == AT91C_ADC_ENDRX)
{//ENDRX bit set when reach the end of buffer.
pADC->ADC_RNCR = AD_DATA_BUFFER_SIZE;
}
*AT91C_AIC_EOICR = 0; // end of interrupts
}
void Configure_AD(void)
{
int i;
volatile AT91PS_ADC pADC = AT91C_BASE_ADC; // create a pointer to USART0 structure
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC; // pointer to AIC data structure
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; // pointer to PIO data structure
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; // pointer to PMC data structure
#define AD_PRESCAL 1
#define AD_STARTUP 1
#define AD_SHTIM 2
// Enable peripheral clock
pPMC->PMC_PCER = 1 << AT91C_ID_ADC;
//Notice: After ADC_SR = 0xc000 after Reset;
pADC->ADC_CR = AT91C_ADC_SWRST; //Reset AD
//Rxternal trigger: TIOA2 output pulse; Get data using ISP.
pADC->ADC_MR = ((AD_SHTIM << 24) | (AD_STARTUP << 16) | (AD_PRESCAL <<8) | AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA2);
pADC->ADC_CHER = AT91C_ADC_CH4; //channel 4 enable
//Configure PDC; Write Counter Register reset ADC_SR.
pADC->ADC_PTCR = AT91C_PDC_RXTDIS ;
pADC->ADC_RPR = (unsigned long)Buffer1; // Receive Pointer Register
pADC->ADC_RCR = AD_DATA_BUFFER_SIZE; // Receive Counter Register
pADC->ADC_RNPR = (unsigned long)0; // Receive Next Pointer Register
pADC-> ADC_RNCR = 0 ; // Receive Next Counter Register
pADC->ADC_PTCR = AT91C_PDC_RXTEN ; //Enable PDC
pADC->ADC_IER = AT91C_ADC_ENDRX | AT91C_ADC_RXBUFF; //enable interrupt on transfer complete
pAIC->AIC_IDCR = (1<<AT91C_ID_ADC);
pAIC->AIC_SVR[AT91C_ID_ADC] = (unsigned int)ISR_adc;
pAIC->AIC_SMR[AT91C_ID_ADC] = (AT91C_AIC_PRIOR_LOWEST | 0x4 );
pAIC->AIC_IECR = (1<<AT91C_ID_ADC);
}
I have PIC18F87J11 with 25LC1024 external EEPROM, and I would like to store some data on it and be able to read it later on. I have done some research, but unfortunately I could not find a tutorial that uses similar board as mine. I am using MPLAB IDE with C18 compiler.
PIC18F87J11
Note: two more links are written as comment below.
This is where my problem is ...
In order to write to the 25LC1024 external EEPROM I followed the tutorial from microchip. The first problem is that this tut is written for PIC18F1220 and I'm using PIC18F87J11. So upon opening the project I get two files not found error, but I simply ignored them.
PICTURE
I copied the file AN1018.h and AN1018_SPI.c to the project I am working on, and I copied some piece of code from AN1018.c file.
Code from AN1018.c file
void main(void)
{
#define PAGESIZE 16
static unsigned char data[PAGESIZE]; // One-page data array
static unsigned char i;
init(); // Initialize PIC
data[0] = 0xCC; // Initialize first data byte
/* Low-density byte function calls */
LowDensByteWrite(data[0], 0x133); // Write 1 byte of data at 0x133
data[0] = 0xFF;
LowDensByteRead(data, 0x133);
printf("%x",data);
while(1){};
}
void init(void)
{
ADCON1 = 0x7F; // Configure digital I/O
PORTA = 0x08; // Set CS high (inactive)
TRISA = 0b11110111; // Configure PORTA I/O
PORTB = 0; // Clear all PORTB pins
TRISB = 0b11111100; // Configure PORTB I/O
}
My second problem is that the output message is always 1e0. In other words, I do not know if the write was successfully made or not. Also I am not sure about what I might be missing.
If I can receive some kind of help, I would appreciate it. To sum up everything, I want to store data to my external EEPROM and retain it when needed. Please know I am a beginner with Microcontroller programming.
As a first step (before reading & writing) you have to be sure that your SPI interface (hardware and software) is correctly configured. To check this step you can read the "Status Register" from the 25LC1024. Look the datasheet for "RDSR", the instruction to send to the eeprom should be 0b00000101 so (int)5.
Here some code for 18F* + 25LC* wirtten in sdcc of a really old project. The code is very basic, no external library used, you just have to replace register variable names and init config for your pic.
Some code comes from here, thanks to bitberzerkir!
spi.c
#ifndef SPI_HH
#define SPI_HH
#define SpiWrite(x) spiRW(x)
#define SpiRead() spiRW(0)
unsigned char spiRW(unsigned char data_){
SSPBUF = data_;
while(!PIR1bits.SSPIF);
PIR1bits.SSPIF = 0;
return SSPBUF;
}
void SpiInit() {
SSPSTAT = 0x40; // 01000000
SSPCON1 = 0x20; // 00100000
PIR1bits.SSPIF = 0;
}
#endif
eeprom.c
Note: Since the addr of 25LC1024 are 3x8bits make sure your compiler 'long' type has at least 24bit
#ifndef EEPROM_HH
#define EEPROM_HH
#include "spi.c"
#define CS PORTCbits.RC2
void EepromInit() {
SpiInit();
CS = 1;
}
unsigned char EReadStatus () {
unsigned char c;
CS = 0;
SpiWrite(0x05);
c = SpiRead();
CS = 1;
return c;
}
unsigned char EWriting() {
unsigned char c;
CS = 0;
SpiWrite(0x05);
c = SpiRead();
CS = 1;
return c & 1;
}
unsigned char EReadCh (unsigned long addr) {
unsigned char c;
// Send READ command and addr, then read data
CS = 0;
SpiWrite(0x03);
// Address in 3x8 bit mode for 25lc1024
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
c = SpiRead();
CS = 1;
return c;
}
void EWriteCh (unsigned char c, unsigned long addr) {
// Enable Write Latch
CS = 0;
SpiWrite(0x06);
CS = 1;
// Send WRITE command, addr and data
CS = 0;
SpiWrite(0x02);
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
SpiWrite(c);
CS = 1;
}
#endif
main.c
Set your init according to the datasheet
#include <pic18fregs.h>
#include "eeprom.c"
void main(void) {
char out;
TRISB = 0x01;
TRISC = 0x00;
PORTB = 0x00;
PORTC = 0x00;
EepromInit();
EWriteCh('a', 0x00);
out = EReadCh(0x00);
while(1);
}
If you want to read/write a buffer take care of pagination. Eg here:
// Page byte size, 64 for 25lc256 and 256 for 25lc1024
#define PSIZE 256
// Addr mem limit 7FFF for 25lc256, 1FFFF for 25lc1024
#define MLIMIT 0x1FFFF
void EReadBuff (unsigned char c[], unsigned long dim, unsigned long addr) {
unsigned int i;
// Send READ command and addr, then read data
CS = 0;
SpiWrite(0x03);
SpiWrite(addr>>16);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
for(i = 0; i < dim; ++i)
c[i] = SpiRead();
CS = 1;
}
void EWriteBuff (unsigned char c[], unsigned long dim, unsigned long addr) {
unsigned char i;
unsigned int begin = 0;
unsigned int end = dim > PSIZE ? PSIZE : dim;
while (end > begin && addr + end <= MLIMIT) { // check if addr is a siutable address [0, MLIMIT]
// Enable Write Latch
CS = 0;
SpiWrite(0x06);
CS = 1;
// Send WRITE command, addr and data
CS = 0;
SpiWrite(0x02);
SpiWrite(addr>>8);
SpiWrite((unsigned char) addr);
for(i = begin; i < end; ++i)
SpiWrite(c[i]);
CS = 1;
while(EWriting());
dim -= PSIZE;
begin += PSIZE;
addr += PSIZE;
end = begin + (dim > PSIZE ? PSIZE : dim);
}
}
#endif
I think before directly using the AN1018.h/AN1018_spi.c you will need to verify that it is compatible with your micro-controller. I recommend to check the datasheet of both micro-controllers and see the difference specifically for SPI module as the external EEPROM which you are using will be connected to SPI bus. If these two micro-controller has same register configuration/module for SPI then you can use it else you will have to write the driver on your own. You can use AN1018_spi.c for reference I guess you will just need to change some registers if required.
Then in you init function, you are not initializing SPI module, you will need to specify correct SPI clock, SPI mode based on your external device. Once you have properly initialize SPI module. You will need to write EEPROM_Read/EEPROM_Write function. In which you will have to following protocol given in datasheet of your external device for sending/receiving data from device using.
hi i googled and get a very good website Where i found post on Interfacing external EEPROM with PIC Microcontroller via i2c protocol with FM24C64 and the code which they given in post which i tested and working fine. i give that link may it help you. http://www.nbcafe.in/interfacing-external-eeprom-with-pic-microcontroller/
First ,thanks for the good suggestion from artless noise.
I choose sharing 3G - 4G-1 kernel space address with usr task (vaddr : 0 - 4G) to switch tasks.
I think tasks switching would be like this :
a clock interrupt comes when usr task is running in its own address space
branch to the 3G of usr address space (also it is kernel 3G space).
context saving
schedule ()
{
....
switch_ttb_base (ttb_base); // I think it is the key,(taskA --> TaskB)
// when ttb_base switched,address space is changed,
// it looks like TaskB is interrupted && arrives here.
// So,after context restored,it would return to TaskB
// which looks like TaskB is interrupted just now !
....
}
context restoring
branch to new usr task
So,to share the kernel 3G address ,I should copy the page_tbls from kernel 3G address to usr page_tbls.
Here is my code, (ARM920T,S3C2440)
#define INIT_L1_BASE (0x30100000) /* 16K */
#define INIT_L2_BASE (0x30104000) /* 64k */
#define KERNEL_IMG_SIZE (0x20000) /* 128 K */
#define KERNEL_CODE_START (0xC0000000) /* 3G start */
#define TTB_BASE (0x30000000)
#define PAGE_DIR (TTB_BASE)
#define TTB_FULL_SIZE (0x4000) /* 16K */
#define PAGE_TABLE (TTB_BASE+TTB_FULL_SIZE)
#define PAGE_DIR_SIZE (0x4000) /* 16k */
#define PAGE_TBL_SIZE (0x10000) /* 64K */
void copy_kernel_page_tbls (unsigned dest_ttb,unsigned vaddr,unsigned size)
{
if ((size & 0xFFFFF) || (vaddr & 0xFFFFF)) /* 1M alignment */
panic ( "trying to copy page tables with non-1M alignment !\n" );
volatile unsigned *_from_page_dir,*_to_page_dir;
_from_page_dir = (volatile unsigned *)(TTB_BASE);
_to_page_dir = (volatile unsigned *)dest_ttb;
unsigned l1_idx;
unsigned i = 0,j = 0,k = 0,page;
volatile unsigned *_to_page_tbl,*_from_page_tbl;
for (k = 0 ,size >>= 20 ; k < size ; k ++,vaddr += 0x100000 )
{
l1_idx = vaddr>>20;
if ( !(_from_page_dir[l1_idx] & ~0x3FF))
continue;
if ( !(_to_page_dir[l1_idx] & ~0x3FF) ) { /* if dest page dir unit is empty */
i = l1_idx & ~3;
if ((_to_page_dir[i+0] & ~0x3FF) || (_to_page_dir[i+1] & ~0x3FF)
|| (_to_page_dir[i+2] & ~0x3FF) || (_to_page_dir[i+3] & ~0x3FF) )
{
panic ( "page dir corrupts with l1_idx %d !\n",l1_idx );
}
if (!(page = find_free_page ()))
panic ( "no more free page !\n" ); /* alloc a page page dir*/
wordset ((void*)page,AP_FAULT_ALL|CB|TTB1_SPG,0x1000); /* set all be fault */
_to_page_dir[i+0] = (page + 0x000)|DOMAIN_SYS|TTB0_COARSE; /* small page 1st 1KB */
_to_page_dir[i+1] = (page + 0x400)|DOMAIN_SYS|TTB0_COARSE; /* small page 2nd 1KB */
_to_page_dir[i+2] = (page + 0x800)|DOMAIN_SYS|TTB0_COARSE; /* small page 3rd 1KB */
_to_page_dir[i+3] = (page + 0xC00)|DOMAIN_SYS|TTB0_COARSE; /* small page 4th 1KB */
}
_from_page_tbl = (volatile unsigned*)(_from_page_dir[l1_idx] & ~(0x3FF));
_to_page_tbl = (volatile unsigned*)(_to_page_dir[l1_idx] & ~(0x3FF));
/* continue copying .... */
for (j = 0 ; j < 256 ; j++ ) { /* 256 * 4K */
if (_from_page_tbl[j] & ~0xFFF)
_to_page_tbl[j] = _from_page_tbl[j]; /* FIXME : change attribute */
}
}
}
I call it like this
copy_kernel_page_tbls (INIT_L1_BASE,KERNEL_CODE_START,1<<30); /* 1G size */
the clock handler is
extern unsigned long __ticks;
#define __DEBUG__
static
void schedlue ( void )
{
// ..............
sync_dcaches ();
invalidate_icaches ();
invalidate_dcaches ();
invalidate_tlbs();
set_ttb_base(current_p->ttb_base);
}
void __do_timer0 (void)
{
static unsigned i = 0;
++ i;
current_p = task_st[i & 1]; /* just 2 tasks */
__ticks ++;
.....
.....
schedule ();
}
ARM just halt.I don't know why ? Any help appreciated !
I did a mmu test to test mmu cache operations
I switch ttb base with :
void change_ttb_base (unsigned ttb)
{
sync_dcaches ();
invalidate_icache ();
invalidate_dcaches ();
set_ttb_base (ttb);
invalidate_tlbs ();
}
on my s3c2440 board ,0x30000000 - 0x34000000 is the sdram address,I do the test on sdram address space,
ttb_base switched successfully!
but when the code run at the high 3G address ,after I called change_ttb_base (),ARM just halt.I guess,the code running in high 3G address need MMU address translation,I changed ttb_base and invalidate all i & d cache and tlbs ,so ARM core don't know what the next step is ,so just halt .....
Is that right ???