How to make my ADC work in tm4c123gxl microcontroller? - arm

My steps are as follows:
enabling clock for ADC and port of AIN10 (PB4).
Disabling the respective bits in DEN and DIR register corresponding to pin B4.
Enabling the corresponding pins in AFSEL register and PCTL register*.
Setting the registers for: Sampling rate,priority(SS3) etc as shown in the code.
Then I trigger it in another function but somehow my ADC isn't reading any other value of applied voltage.
My first question is about PCTL and what value we need to enable ADC on it?
I have been trying to solve it for about a day now but I still haven't figured it out yet. Any help is much appreciated.
// Register definitions for clock enable
#define SYSCTL_RCGCGPIO_R ( * ( ( volatile unsigned long *) 0x400FE608 ) )
#define SYSCTL_RCGCADC_R ( * ( ( volatile unsigned long *) 0x400FE638 ) )
#define GPIO_PORTB_AFSEL_R ( * ( ( volatile unsigned long *) 0x40058420 ) )
#define GPIO_PORTB_PCTL_R (*(( volatile unsigned long *)0x4005952C))
// Register definitions for GPIO port B ;;;;; AIN10 = PB4
#define GPIO_PORTB_DATA_R ( * ( ( volatile unsigned long *) 0x400053FC) )
#define GPIO_PORTB_DIR_R ( * ( ( volatile unsigned long *) 0x40005400 ) )
#define GPIO_PORTB_DEN_R ( *( ( volatile unsigned long *) 0x4000551C) )
// Register definitions for ADC0 and Sample Sequencer 3
#define ADC0_PC_R ( * ( ( volatile unsigned long *) 0x40038FC4 ) )
#define ADC0_SSPRI_R ( * ( ( volatile unsigned long *) 0x40038020 ) )
#define ADC0_ACTSS_R ( * ( ( volatile unsigned long *) 0x40038000 ) )
#define ADC0_IM_R ( * ( ( volatile unsigned long *) 0x40038008 ) )
#define ADC0_RIS_R ( * ( ( volatile unsigned long *) 0x40038004 ) )
#define ADC0_ISC_R ( * ( ( volatile unsigned long *) 0x4003800C) )
#define ADC0_SAC_R ( * ( ( volatile unsigned long *) 0x40038030 ) )
#define ADC0_PSSI_R ( * ( ( volatile unsigned long *) 0x40038028 ) )
#define ADC0_SSCTL3_R ( * ( ( volatile unsigned long *) 0x400380A4 ) )
#define ADC0_SSFIFO3_R ( * ( ( volatile unsigned long *) 0x400380A8 ) )
unsigned char Lookup_7Seg_Disp [ 12 ] = {0xC0 , 0xF9 , 0xA4 , 0xB0 , 0x99 ,
0x92 , 0x82 , 0xF8 , 0x80 , 0x90 , 0xC6};
unsigned char Temperature_Value [ 3 ] = {0 , 0 , 0xA} ;
unsigned char i , value=0;
unsigned int ADC_value = 0 , voltage = 0 ;
int maxVoltage=0;
void ADC_Init() {
volatile unsigned long delay;
SYSCTL_RCGCGPIO_R |= 0x01; //Enable Clock for Port A
SYSCTL_RCGCADC_R |= 0x1; //Enable ADC0
delay = SYSCTL_RCGCGPIO_R; //Delay for clock to settle down
GPIO_PORTB_DIR_R &= ~(0x10);//PB4 as input
GPIO_PORTB_DEN_R &= ~(0x10);//PB4 as analog type
GPIO_PORTB_AFSEL_R |= 0x10;
GPIO_PORTB_PCTL_R |= 0x10;
//Clear sampling rate
ADC0_PC_R &= 0x00;
//Set sampling rate to 125ksps
ADC0_PC_R &= 0x01;
//Set priority to SSFI3
ADC0_SSPRI_R |= 0x3210;
//Disable sample sequence 3 befor configuration
ADC0_ACTSS_R &= ~0x8;
//Enable TS0, IE0 and END0 bits
ADC0_SSCTL3_R |= 0xE;
//Enable 16x hardware oversampling
ADC0_SAC_R |= 0x4;
//Disable Interrupt by writing 0 to corresponding bit
ADC0_IM_R &= ~(0x8);
//Activate sample sequencer
ADC0_ACTSS_R |= 0x8;
}
void SystemInit() {
}
void ADC_Voltage(void) {
ADC0_PSSI_R |= 0x8;
while ((ADC0_RIS_R & 0x8)==0);
ADC_value = (ADC0_SSFIFO3_R & 0xFFF);
voltage = (ADC_value)*44;
if(voltage>maxVoltage){
maxVoltage=voltage;
}
ADC0_ISC_R |= 0x08;
}
void delay(unsigned long counter) {
int i;
for(i=0;i<counter;i++)
{}
}
int main(void) {
ADC_Init();
delay(1000);
ADC_Voltage();
maxVoltage=maxVoltage*0.707;
}

I'm not sure if you solved this yet. I typically use TI's supplied driverlib that you can find in TivaWARE, so I don't know all the registers for doing this DRM off the top of my head. Double check that you are muxing the pin properly. The other thing to look at is the sample sequencer. The ADCs are on sample sequencers and you have to set them up as well, for the number of samples, the source of the samples, etc. You can test your ADC configuration by setting up the sequencer to read from the internal temperature sensor instead of an external pin to at least get that section of the code debugged. If that works, and you then switch it to an external pin and it doesn't work anymore, then you'll know the problem is the pin muxing.
Is there a compelling reason you aren't using TI's supplied driver library? It would have taken minutes to set up by using that instead of performing DRM. if code size is a concern, the tm4c also has driverlib on ROM
Even if you cannot use driverlib for some reason, take a look at the driverlib source, the tivaware peripheral driver library user guide and the example code. You'll see the driverlib calls that are required to set this up, and can track that back to the registers that need configuring.

Related

Why am I getting Segmentation fault. Raspberry pi 4 C Programming

#include <linux/module.h>
#include <linux/kernel.h>
//#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
//#include <linux/input-polldev.h>
//#include <linux/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
/*
MAHIR SHAHRIAR
30027575
CPSC 359
ASSIGNMENT 2
*/
#define GPIO_CLOCKPIN 23 // pin used for clock output GPIO 11 (SPI_SCLK)
#define GPIO_LATCHPIN 21 // pin used for latch output GPIO 9 (SPI_MISO)
#define GPIO_DATAPIN 19 // pin used for data input from controller GPIO 10 (SPI_MOSI)
#define GPIO_POWERPIN 1 // 3.3 VOLT POWER SOURCE Programmble input to set high/low
#define GPIO_GROUNDPIN 9 // Pin used for grounding
#define GPIO_BASEADDRESS 0xfe200000 // Base address used to offset to other registers
//volatile unsigned *gpio = (unsigned*)0xfe200000; // gpio pointer to base address
volatile uint32_t *gpio = (unsigned*)0xfe200000;
volatile uint32_t *GPFSEL1 = (unsigned*)0xfe200000 + 0x04/4; //pointer to register GPFSEL1 for pins 10-19
volatile unsigned *GPFSEL2 = (unsigned*)0xfe200000 + 0x08/4; //pointer to register GPFSEL2 for pins 20-29
volatile unsigned *GPSET0 = (unsigned*)0xfe200000 + 0x1c/4; //pointer to register GPSET0 for setting high
volatile unsigned *GPCLR0 = (unsigned*)0xfe200000 + 0x28/4; //pointer to register GPCLR0 for setting low
volatile unsigned *GPLEV0 = (unsigned*)0xfe200000 + 0x34/4; //pointer to register GPLEV0 for reading data from pin
volatile unsigned *GPIO_PUP_PDN_CNTRL_REG1 = (unsigned*)0xfe200000 + 0xe8/4; //pointer to register for controlling pull up pull down
// INIT GPIO Function takes user inputs for Initializing a particular GPIO Pin number.
// It takes data such as the PIN NUMBBER , string "input" or "output" ,
// string "high" or "low " and string "pullup" or "pulldown"
// Depending on the arguments passed into the Init_GPIO function or subroutine
static void Init_GPIO(int pin_number, char type, char high_low, char pullup_pulldown) {
// setting valueinput valueoutput and mask to set the input output of the pin type
int valueinput = 0b000 << ( (pin_number-10)*3 ); // bits to be set for input
int valueoutput = 0b001 << ( (pin_number-10)*3 ); // bits to be set for output
int mask = 0b111 << ( (pin_number-10)*3 ); // for ensuring other bits dont change
// condition to check which register to access for the bits and setting to input or output based on
// function calls from main and arguments passed
if(pin_number<=19){
if(type == 'i'){
printf("%x", GPFSEL1);
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask); //problem
}
else if(type == 'o'){
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
if(pin_number > 19 && pin_number <=29 ){
if(type == 'i'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueinput * mask);
}
else if(type == 'o'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
}
// Setting the pin to either high or low
if(high_low == 'h'){
//*GPSET0 = 1 << pin_number;
}
else if(high_low == 'l'){
//*GPCLR0 = 1 << pin_number;
}
else{
// high low not specified
printf("high low not specified please use 'h' or 'l' ignore if not specifying highlow for pin\n");
}
}
// Setting if the pin uses pull up or pull down register
int value_pullup = 0b01 << ( (pin_number -16)*2 );
int value_pulldown = 0b10 << ( (pin_number -16)*2 );
mask = 0b11 << ( (pin_number -16)*2 );
if(pullup_pulldown == 'p'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pullup) & mask;
}
else if(pullup_pulldown == 'n'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pulldown) & mask;
}
else {
// user does not set any pull up or pull down value for the assigned pin
printf("pull up pull down not specified please use 'p' or 'n' ignore if not specifying pullup pulldown for pin\n");
}
}
void main() {
printf("pointer address %p " , gpio);
Init_GPIO(18, 'i', 'l', 'p');
volatile uint32_t valueinput = 0b000 << ( (18-10)*3 ); // bits to be set for input
volatile uint32_t valueoutput = 0b001 << ( (18-10)*3 ); // bits to be set for output
volatile uint32_t mask = 0b111 << ( (18-10)*3 );
*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask);
}
I am getting segmentation error for the last line in main. I dont know why this is doing that. How do I fix the issue I am trying to change the bits in the register GPFSEL1 for the raspberry pi 4 GPIO for changing the input mode by changing bits to 000 for my pin 18 for putting in into input mode. Any help or direction would be greatly appreciated!

implicit conversion changes signedness: 'int' to 'unsigned long' in c using keil

I'm new in the programingo of STM32, I've whatched aome tutorials, but whe I've put in practice the last, keil give me some warnings (the tutorial is about of GPIO INPUT OUTPUT LIBRARY FROM SCRATCH).
the warnigs are:
gpi_drive.c(35): warning: implicit conversion changes signedness: 'int' to 'unsigned long' [-Wsign-conversion]
*CR |= ((dir<<(pin*4)) | (opt<<(pin*4+2)));
~~ ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
gpi_drive.c(34): warning: variable 'CR' may be uninitialized when used here [-Wconditional-uninitialized]
*CR &= ~(0xfu<<(pin)*4); /*Reset the target pin*/
^~
gpi_drive.c(7): note: initialize the variable 'CR' to silence this warning
volatile unsigned long * CR;
#include "gpi_drive.h"
void init_GP(unsigned short port, unsigned short pin, unsigned short dir, unsigned short opt)
{
volatile unsigned long * CR;
unsigned short offset = 0x00;
if (pin > 7)
{
pin -=8;
offset = 0x01;
}
if (port == 1)
{
RCC_APB2ENR |= 4; /*Enabling port A*/
CR = (volatile unsigned long *) (&GPIO_A + offset);
}
if (port == 2)
{
RCC_APB2ENR |= 8; /*Enabling port B*/
CR = (volatile unsigned long *) (&GPIO_B + offset);
}
if (port == 3)
{
RCC_APB2ENR |= 0x10; /*Enabling port C*/
CR = (volatile unsigned long *) (&GPIO_C + offset);
}
*CR &= ~(0xfu<<(pin)*4); /*Reset the target pin*/ //this is the line 34
*CR |= ((dir<<(pin*4u)) | (opt<<(pin*4+2))); //this is the line 35
}
This is the code that I have, I don't know how to make that the numbers of the rows appears, sorry for this. And if you need more information let know, and thak you so much

UART only transmitting first and last character of string (PIC16F877A simulation through proteus)

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.

errors encountered while interfacing eeprom with microcontroller

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.

Saving data to External EEPROM with PIC18

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/

Resources