## Access I2C EEPROM (was Reading value from AtMega328P pin)

84 posts / 0 new
Author
Message

I'm trying to read the value present on a pin of my AtMega328P.

I'm doing it by:


/*..
**..code
**..more code
**/

DDRB &= ~(1 << PB1); //set input mode on this pin
PORTB &= ~(1 << PB1);//not sure if I need to do this

//set PB1 pin back to output mode
DDRB |= (1 << PB1);

But the compiler says:

error: expected ‘;’ before numeric constant
^
|

How can I do this?

Last Edited: Wed. Nov 2, 2016 - 12:22 AM
#include <avr/io.h>

int main()
{
DDRD |= (1<<PD7);
DDRC &=~ (1<<PC0);

while(1)
{
if(PINC & (1<<PC0))
{
PORTD |= (1<<PD7);
}
else

PORTD &=~ (1<<PD7);
}
return 0;
}

You may try this.

শূন্য  - The ZeRo

Last Edited: Sun. Oct 30, 2016 - 02:44 PM

eRony wrote:

#include <avr/io.h>

int main()
{
DDRD |= (1<<PD7);
DDRC &=~ (1<<PC0);

while(1)
{
if(PINC & (1<<PC0))
{
PORTD |= (1<<PD7);
}
else

PORTD &=~ (1<<PD7);
}
return 0;
}

You may try this.

I need to save the value of PB1 somewhere! Where in your code are you saving the value?

Before this turns into another 70+ post count over a seemingly simple function can you explain what it is you want to do and why you need to save the value of a single pin?

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:
Before this turns into another 70+ post count over a seemingly simple function can you explain what it is you want to do and why you need to save the value of a single pin? Jim

jgmdesign, I'm sorry to ask, but is there any problem with threads with a lot of posts???

I'm just trying to learn. If it takes over 70 posts and it is not allowed, then, I'm sorry... I'll stop asking questions here!

And probably is your question that is going to turn this thread is a huge thread, but sure, I can tell you why I'm reading and storing a single pin's value!

I'm trying to write my own version of software to interface external memory ICs with AtMega328P... And yes, I already took a look into Peter Fluery's I2C libraries and I don't know how to use them. They have too many variables that I just don't know! All those TWxxxxxx macros that I cannot find any reference to what they are. So I decided to try to make my own version of the software.

The reason I want to store a pin's value is to check the ACK state aka acknowledge bit!

Last Edited: Sun. Oct 30, 2016 - 03:41 PM

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

There is nothing wrong with asking questions but the proper way to start a thread is to explain what you are trying to achieve and why you need to do certain things.

I don't care If the thread goes 70 posts or more. But please provide all the pertinent information up front. Not fragments of information here and there like in your LCD thread. That's all.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Read the bit manipulation 101 thread in the tutorial forum. Report back if there's anything you don't understand .  As you'll read there you read the state of PB1 with something like:

if (PINB & (1 << PB1) )  {. . .

clawson wrote:

As you'll read there you read the state of PB1 with something like...

Although, without wanting to confuse the OP, he should be aware that some sample code he'll find online might show something like this...

#include <io.h>
#include <stdint.h>

uint8_t val;

void main(void)
{
DDRB &= ~(1 << PORTB1); //set input mode on this pin
PORTB &= ~(1 << PORTB1);//not sure if I need to do this

//set PB1 pin back to output mode
DDRB |= (1 << PORTB1);
}

...which is perfectly valid in Codevision.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

#include <avr/io.h>

int main()
{
DDRC &=~ (1<<PC0);
int pin_status;

while(1)
{
if(PINC & (1<<PC0))
{
pin_status = 1
}
else
pin_status = 0;

}
return 0;
}


Hope you realize it.

শূন্য  - The ZeRo

Last Edited: Sun. Oct 30, 2016 - 04:33 PM

Brian Fairchild wrote:

I'm not sure it is a spelling mistake!

PINT suggests to me something like "P integer". I want to read the state of a pin, so "pin to read" doesn't look like a spelling mistake to me! Anyway, my major concern is not my English language skills, as I'm not English native! But I can also understand your reasoning!

jgmdesign wrote:
There is nothing wrong with asking questions but the proper way to start a thread is to explain what you are trying to achieve and why you need to do certain things. I don't care If the thread goes 70 posts or more. But please provide all the pertinent information up front. Not fragments of information here and there like in your LCD thread. That's all. Jim

Ok jmdesign... You have a point there! The reason why I have not said it all was to try to narrow the replies to strictly what I needed. But I absolutely understand that if you all know my goal, probably we can find an answer faster!

Brian Fairchild wrote:

clawson wrote:

As you'll read there you read the state of PB1 with something like...

Although, without wanting to confuse the OP, he should be aware that some sample code he'll find online might show something like this...

#include <io.h>
#include <stdint.h>

uint8_t val;

void main(void)
{
DDRB &= ~(1 << PORTB1); //set input mode on this pin
PORTB &= ~(1 << PORTB1);//not sure if I need to do this

//set PB1 pin back to output mode
DDRB |= (1 << PORTB1);
}

...which is perfectly valid in Codevision.

You mean that there is similar code to that piece of code I posted on the Internet?

Atmel Toolchain complains about the code that way! Not sure why you're able to compile the code using CodeVision!

Last Edited: Sun. Oct 30, 2016 - 06:25 PM

Yeah but he's not using Codevision? Surely that's the point of this thread? He's found some Codevision code and tried to use it in GCC and that's been rejected. That's why I'm advising him about standard code that will work in any compiler (even though that CV syntax is nice if you can use it)

PsySc0rpi0n wrote:

You mean that there is similar code to that piece of code I posted on the Internet?

I didn't bother to look. I assumed that since you used PINB.1 that you'd found some code online meant for Codevision.

PsySc0rpi0n wrote:

Not sure why you're able to compile the code using CodeVision!

Well I am. The code I posted compiles perfectly in Codevision.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

PsySc0rpi0n wrote:

I'm not sure it is a spelling mistake!

Trust me, it is.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

How about the OP tell everyo e what IDE you are using to write your code in. Like I said. The more you tell us the better the answers and less back and forth.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

And posts the whole code.

There's no way the code posted in #1 will compile in any compiler without lots of errors, certainly more than just the one the OP mentioned.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

I suggest everyone read the OP's post #5. He does not understand Peter Fleurys TWI library so he wants to write his own library instead.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Brian, you clearly haven't been party to his interminable thread about LCD? There is no doubt in my mind that he's using avr-gcc.

Hello,

What kind of memory are you trying to interface to the ATmega328p?   Parallel EEPROM, parallel Static RAM,  serial EEPROM, or serial SRAM?  Serial EEPROM is the only type that uses the I2C interface.   Serial SRAM uses the SPI interface and the parallel chips will use between ten to twelve in/out lines ( for Data0-Data7, ReadStrobe\, WriteStrobe\, ChipEnable 1 and maybe chip enable 2.)

Is this Mega328P part of an Arduino UNO/nano system? if yes then I suggest using the "Audrey" libraries for Wire.h and SPI.h interfacing.  Parallel interfacing is only for when very high speed interfacing is needed (or your company has a stockpile of these types of memory chips).

Ok, everyone, I'm sorry for the lack of information. I always try to stick to what I really needed so that we don't get lost with other details like, if I post the whole code, I know that will rain down lots of questions about my coding method! I'm new to C programming oriented to micro controllers, so there's a lot of habits I don not know and do not understand at a first glance!

Now, trying to answer to everyone by order:

Brain Fairchild:

You mean that his code is valid in CodeVision?

#include <io.h>
#include <stdint.h>

uint8_t val;

void main(void)
{
DDRB &= ~(1 << PORTB1); //set input mode on this pin
PORTB &= ~(1 << PORTB1);//not sure if I need to do this

//set PB1 pin back to output mode
DDRB |= (1 << PORTB1);
}

If so, lucky you... I can't compile it.

About the typing mistake, I can give whatever name I want to my macros, so PIN_TO_READ is perfectly valid and there was no mistake made by me when I typed the macro's name! And more, that name was just an example! I have no macro with that name in my code!

About posting the whole code, this forum is not very reasonable when we use the tags to show the code here! It shows up all in green which is almost the same as paste it to here as plain text! That's why I avoid to post more than a few lines of code here!

But I'll use, for instance, ideone.com site to post code and share the link here!

jgmdesign, I don't know if it can be called "my own library". I like more to call it my own version of the code! I just want to create a couple of functions that allows me to read and write bytes from/to an external memory device!

clawson, everyone talks about the big thread about LCD. I don't know what is wrong with long threads! Anyway, yes, I'm using Atmel Toolchain, version 3.4, I guess!

Ok, I'm going to try to say everything I can remember about what I'm trying to do!

As I'm new to external memory devices and to I2C protocol, there are a lot of questions about these two matters! I have already read a bit about I2C protocol and I'm also constantly checking my external memory device datasheet!

But as for now I'm using:

USB-to-serial converter to communicate with AtMega328P-PU that is siting on a breadboard.

I'm using a 16MHz crystal.

I'm trying to interface the AtMega328P-PU with a Microchip 24LC08B external memory device! This is the datasheet I'm using.

To compile the code I'm using avr-gcc from Atmel Toolcahin.

And tu upload the firmware I'm using avrdude, as usual!

This is my code... I know that it will probably won't work, but the code is a work in progress, and fixing the problems will be my way to understand things

https://ideone.com/VErKsX

I'm posting the code just to give you guys a context! Of course you're free to pint the code's problems but that is what will make the thread so huge that everybody will talk about it for ages! :p

PsySc0rpi0n wrote:
Brain Fairchild: You mean that his code is valid in CodeVision? #include #include #define PIN_TO_READ PINB.1 uint8_t val; void main(void) { DDRB &= ~(1 << PORTB1); //set input mode on this pin PORTB &= ~(1 << PORTB1);//not sure if I need to do this val = PIN_TO_READ; //set PB1 pin back to output mode DDRB |= (1 << PORTB1); } If so, lucky you... I can't compile it.

??? Weren't you asked about toolchain and version earlier?  Why have you chosen not to answer thse queries?

Are you using CodeVision or not?

If you are using CodeVision, what version?

If you are using CodeVision, why "can't compile it"?  If you are getting errors, post them here.  >>After<< telling what version you are using.

As discussed above, from your other thread it does NOT appear that you are using CodeVision.

I see you have now corrected the typo that you claimed earlier did not exist.

I'm starting to get quite confused.  Several respondents have told you the generic (non-tooclchain-dependent) way to read a pin.

PsySc0rpi0n wrote:
PIN_TO_READ is perfectly valid and there was no mistake made by me when I typed the macro's name!

You did NOT type that.  You typed...

PsySc0rpi0n wrote:

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

There was a typo in your original code. This was pointed out to you, but you seem to argue.

Ok, you want to learn about i2c and talk to a i2c eeprom.

You need to do some reading first, otherwise you'll skip some fundamental things.

1.i2c spec - this is the source of knowlege with i2c.

http://esd.cs.ucr.edu/webres/i2c...

You can safely ignore the stuff with multimaster- as you don't need this for a simple master/slave arrangement.

2. The mega328 datasheet - especially the section on the port pins. Understand the combinations of ddr and port bits.

3. Bit twiddling: https://www.avrfreaks.net/forum/t...

Hint: for i2c, it is an open collector bus - thus the devices only actively pull the signals down to 0V, for logic '1', they are pulled to VCC via resistors. So, for your port setup, set the required PORT bits to 0. Then twiddle the required DDR bits to select between output (logic 0) and input (logic 1). This means the logic gets inverted when you send. If you don't get what I said - you need to think some more.

If you read the i2c spec, you'll find there are four primitives you need to implement - start,stop,read a byte and write a byte. If you understand all this, you'll find your code will be near identical to just about anyone else's.

If you follow the above, you'll reach your goal faster without having to create long,boring threads where we've seen the same shite over and over again. I can tell you the last time I wrote a bit-bashed i2c library was in the 80's. Nothing much has changed since then. Well, actually the interwebs came about. In them olden days, we had to solve these things by ourselves.

theusch wrote:

PsySc0rpi0n wrote:
Brain Fairchild: You mean that his code is valid in CodeVision? #include #include #define PIN_TO_READ PINB.1 uint8_t val; void main(void) { DDRB &= ~(1 << PORTB1); //set input mode on this pin PORTB &= ~(1 << PORTB1);//not sure if I need to do this val = PIN_TO_READ; //set PB1 pin back to output mode DDRB |= (1 << PORTB1); } If so, lucky you... I can't compile it.

??? Weren't you asked about toolchain and version earlier?  Why have you chosen not to answer thse queries?

Are you using CodeVision or not?

If you are using CodeVision, what version?

If you are using CodeVision, why "can't compile it"?  If you are getting errors, post them here.  >>After<< telling what version you are using.

As discussed above, from your other thread it does NOT appear that you are using CodeVision.

I see you have now corrected the typo that you claimed earlier did not exist.

I'm starting to get quite confused.  Several respondents have told you the generic (non-tooclchain-dependent) way to read a pin.

PsySc0rpi0n wrote:
PIN_TO_READ is perfectly valid and there was no mistake made by me when I typed the macro's name!

You did NOT type that.  You typed...

PsySc0rpi0n wrote:

??? Weren't you asked about toolchain and version earlier?  Why have you chosen not to answer thse queries?

I have not chosen to answer or not to answer to any questions... Nobody asked me what toolchain I was using before post #17.

Are you using CodeVision or not?

If you are using CodeVision, what version?

If you are using CodeVision, why "can't compile it"?  If you are getting errors, post them here.  >>After<< telling what version you are using.

Where the hell have I ever told I was using CodeVision??? The 1st user ever talked about CodeVision was Brain Fairchild in post #9 and I replied in such way suggesting I was not understanding what he had just said. I think clawson understood me in post #14. There was clearly some confusion about what Brain Fairchild said!

Then I said Atmel toolchain was complaining about the error! This could be a tip to tell everyone I was using avr-gcc and avrdude to manage my code compilation and firmware uploading!

As discussed above, from your other thread it does NOT appear that you are using CodeVision.

I see you have now corrected the typo that you claimed earlier did not exist.

I have just realised what Brain Fairchild meant when he told me about the typo... However I haven't corrected it. It's still there! I didn't realised it earlier because I was thinking that Brain Fairchild was referring himself to the macro name and not the macro in the code! I'm sorry for that!

Are you now cleared??? I might be not the best when I start a thread but maybe you should also pay more attention to everyone's posts!

Kartman wrote:

There was a typo in your original code. This was pointed out to you, but you seem to argue.

Ok, you want to learn about i2c and talk to a i2c eeprom.

You need to do some reading first, otherwise you'll skip some fundamental things.

1.i2c spec - this is the source of knowlege with i2c.

http://esd.cs.ucr.edu/webres/i2c...

You can safely ignore the stuff with multimaster- as you don't need this for a simple master/slave arrangement.

2. The mega328 datasheet - especially the section on the port pins. Understand the combinations of ddr and port bits.

3. Bit twiddling: https://www.avrfreaks.net/forum/t...

Hint: for i2c, it is an open collector bus - thus the devices only actively pull the signals down to 0V, for logic '1', they are pulled to VCC via resistors. So, for your port setup, set the required PORT bits to 0. Then twiddle the required DDR bits to select between output (logic 0) and input (logic 1). This means the logic gets inverted when you send. If you don't get what I said - you need to think some more.

If you read the i2c spec, you'll find there are four primitives you need to implement - start,stop,read a byte and write a byte. If you understand all this, you'll find your code will be near identical to just about anyone else's.

If you follow the above, you'll reach your goal faster without having to create long,boring threads where we've seen the same shite over and over again. I can tell you the last time I wrote a bit-bashed i2c library was in the 80's. Nothing much has changed since then. Well, actually the interwebs came about. In them olden days, we had to solve these things by ourselves.

Ok, indeed I need to think a bit more... It's still a bit confusing to me that subject of internal pull-ups and tri-state pins, etc!

I think I have already understood the general concept of I2C protocol... But implementing it can be yet tricky to me! I'm new to this AVR stuff, both hardware and software. No more than 2 months!

Rather than writing your own bit bang library, read the datasheet on the Mega 328's TWI interface thats already there and does the work for you?  It's only a few registers.  The interface is rather easy once it's set up properly.

PsySc0rpi0n wrote:
Then I said Atmel toolchain was complaining about the error! This could be a tip to tell everyone I was using avr-gcc and avrdude to manage my code compilation and firmware uploading!

Um, I have asked you in your other thread if you were using Atmel Studio and I never got a clear answer there as far as I remember.  Just because you are using avr-gcc can mean that you are using only the compiler.  If you are using Studio then we might suggest using the simulator to run your code as an assistant to you.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:

Rather than writing your own bit bang library, read the datasheet on the Mega 328's TWI interface thats already there and does the work for you?  It's only a few registers.  The interface is rather easy once it's set up properly.

PsySc0rpi0n wrote:
Then I said Atmel toolchain was complaining about the error! This could be a tip to tell everyone I was using avr-gcc and avrdude to manage my code compilation and firmware uploading!

Um, I have asked you in your other thread if you were using Atmel Studio and I never got a clear answer there as far as I remember.  Just because you are using avr-gcc can mean that you are using only the compiler.  If you are using Studio then we might suggest using the simulator to run your code as an assistant to you.

Jim

Ok, I'll read that documentation but when I saw the files of Peter Fleury's libraries, they looked like a lot to learn! A lot of registers that I couldn't find what they were! I also saw some straight forward codes that looked like simple to me! There were no TWI's registers. Only the SDA and SCL manipulation, the ACK bit check, a loop to send a byte and not much more!

About Atmel Studio, I think I already said, more than once that I'm using Linux and that I'm using Atmel Toolchain 3.4 but I'm not sure why, I'm keeping being asked what IDE I'm using. As far as I know, Atmel Studio is not Available for Linux! And when I say Atmel Toolchain, doesn't this explicitly means that I'm using avr-gcc and avrdude to do the job? Or does Atmel Toolchain might also mean Atmel Studio?

PsySc0rpi0n wrote:
About Atmel Studio, I think I already said, more than once that I'm using Linux and that I'm using Atmel Toolchain 3.4 but I'm not sure why, I'm keeping being asked what IDE I'm using.
What people have been trying to get to the bottom of is which C compiler you use. Finally you have revealed it is Atmela Toolchain 3.4 in Linux. At least that tells us all it is avr-gcc. What is not entirely clear is which version of avr-gcc it is "3.4" is not a complete version number and, anyway, that is the toolchain version not the compiler version. I imagine if you run "avr-gcc -v" you will see something like 4.8.1 or 4.9.2 or similar.

Anyway the reason this whole thread headed off in a Codevision direction is because in the very first post you included:

#define PIN_TO_READ PINB.1

Across all the code development systems for AVR the only C compiler that could possibly support that syntax is Codevision. So anyone scanning the first post of this thread will see Codevision syntax and naturally assume you are using it. Why else would you use Codevision syntax if not using the Codevision compiler? Makes sense doesn't it?

The reason no other compiler supports that is that C says that when '.' appears in the middle of symbol name it is introducing the name of a sub-element in a struct or union. The rules of C also say that the symbol names of struct or union members (indeed any smbol name in C) cannot start with a digit. So ".1" is illegal syntax.

Now the clever author at HPInfoTech who develops the Codevision compiler (and, admittedly, the authors of C compilers on a few other micros) have said "yeah, it may be considered illegal but it's a very nice way to address the bits of a bye, especially the pins in an IO port." If you read PORTB.5 or PINC.3 you almost immediately think "pin 5 of PORTB or pin3 of PORTC". So it's kind of natural.

But in other C compilers the only way to achieve anything close is to insert at least one letter before the digit so things like PORTB.b5 or PINC.pin3 or whatever. More generally (as the 101 thread I directed you to will show), the access to individual bits in PORT and PIN registers tends to be done using "normal" bit access rather than struct/union access. So things like:

PORTB |= (1 << 5);
PORTB &= ~(1 << 3);

if (PINC & (1 << 3)) { ...

#define PIN_TO_READ PINB.1
/*..
**..code
**..more code
**/



could be done in avr-gcc (or other compilers, even Codevision ;) using:

val = PINB & (1 << 1);

except that would not be quite the same behvaiour because either the bit isn't set so val=0 (same as before) or the bit is set and val=(1<<1) which is the same as val=2. In the Codevision syntax the bit being set would set this to be 1 not 2. You have a couple of ways to achieve that (if it's actually important). Perhaps most obvious:

val = (PINB & (1 << 1)) == (1 << 1);

the bit in the brackets with PINB still gives the answer 2 when the bit is set but then the comparison with (1 << 1) will give a 1/0 answer. So the outcome of this will be 0 if the bit is not set or 1 if it is. Personally I prefer this solution to turn a non-0 into 1:

val = !!(PINB & (1 << 1));

You need to think about that one for a while(!) but, trust me, this will set val to 1 if the bit is set or 0 if it is not.

Another approach is this:

typedef struct {
int b0:1;
int b1:1;
int b2:1;
int b3:1;
int b4:1;
int b5:1;
int b6:1;
int b7:1;
} bits_t;

#define Pinb (*((volatile bits_t *)&PINB)

...

val = Pinb.b1;

Again, this is 100% standard C and should work in any C compiler. I'm effectively defining a new name for PINB called Pinb and this casts a bitfield structure interpretation onto the location so Pinb.b3 means "the state of the 3rd bit at location PINB". This is about as close to the Codevision syntax you can get in avr-gcc. A lot of people will think this is too much hassle and will simply use a solution like:

val = !!(PINB & (1 << 1));

BTW "Atmel Toolchain" does NOT imply avrdude as your programming software - Toolchain does not include it. If you are using avrdude you got/installed it from somewhere else.

EDIT: corrected some typos. Here's some real code using the typedef...

C:\SysGCC\avr\bin>cat test.c
#include <avr/io.h>

typedef struct {
int b0:1;
int b1:1;
int b2:1;
int b3:1;
int b4:1;
int b5:1;
int b6:1;
int b7:1;
} bits_t;

#define Pinb (*(volatile bits_t *)&PINB)

int main(void){
if (Pinb.b1) {
PORTC = 0x55;
}
while(1){
}
}

C:\SysGCC\avr\bin>avr-gcc -save-temps -Os -g -mmcu=atmega16 test.c -o test.elf

C:\SysGCC\avr\bin>avr-objdump -S test.elf

[SNIP!]

0000006c <main>:
} bits_t;

#define Pinb (*(volatile bits_t *)&PINB)

int main(void){
if (Pinb.b1) {
6c:   b1 9b           sbis    0x16, 1 ; 22
6e:   02 c0           rjmp    .+4             ; 0x74 <main+0x8>
PORTC = 0x55;
70:   85 e5           ldi     r24, 0x55       ; 85
72:   85 bb           out     0x15, r24       ; 21
74:   ff cf           rjmp    .-2             ; 0x74 <main+0x8>

00000076 <_exit>:
76:   f8 94           cli

00000078 <__stop_program>:
78:   ff cf           rjmp    .-2             ; 0x78 <__stop_program>


As you can see this code is testing the state of bit 1 in location 0x16 (PINB) to decide whether to skip or not.

Last Edited: Mon. Oct 31, 2016 - 01:07 PM

PsySc0rpi0n wrote:
Ok, I'll read that documentation but when I saw the files of Peter Fleury's libraries, they looked like a lot to learn! A lot of registers that I couldn't find what they were! I also saw some straight forward codes that looked like simple to me! There were no TWI's registers. Only the SDA and SCL manipulation, the ACK bit check, a loop to send a byte and not much more!

You have missed the point of a library to some extent.

In the Mega328 there are six registers associated with the TWI.  The library takes care of the configuration of all of this.  The only thing you need to set in the library is the SCL speed....Traditionally 100khz or 400khz.  This is done in the .c file TWIMASTER.c

You will need to INCLUDE i2cmaster.h in your main.c to use the library.  YOu must also define F_CPU as well

After that, in your code you would write:

i2c_init();

and this will set the SCL for you as it does the math required.  YOu only have to do this once.

After that it's just basic function calls.

i2c_stop();

i2c_write(byte);

All of these functions are explained in the Online Manual here:

http://homepage.hispeed.ch/peter...

In your case, the eeprom you are using does not have an address.  The A0...An lines on the IC are not connected, but the bits normally used in the control word for address are for bank select.  YOU would still use the library normally, you just need to make sure you address the proper bank when you are reading or writing.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

PsySc0rpi0n wrote:
All those TWxxxxxx macros that I cannot find any reference to what they are.

The TWIxxxx you cannot find any reference to are in the 328P datasheet:

The full documentation of them is the whole of chapter 26 onwards...

That chapter makes multiple references to TWAR, TWBR, TWSR and so on. You program the registers and the bits and the block of silicon inside your chip, attached the AVR core will wiggle (and listen) to SDA and SCL at the right moments to do almost all the work of operating I2C (that Atmel call TWI) for you.

The Fleury (and other code) is simply taking what is written in a chapter such as chapter 26 here and putting it into C code so you don't need to bother with all the gory details. As Jim says you just call high level functions like i2c_start(), i2c_write() and Mr. Fleury programs TWBR, TWCR and so on appropriately.

If  you want to sit down with Peter's code and a copy of chapter 26 you can pull it apart line by line to see why he's doing the things the datasheet has told him to. (if very lucky you might even spot an error - but I doubt it).

Or if you have that investigative spirit you could throw away the Fleury code and just sit with a copy of chapter 26 and your C editor and have a crack at trying to provide the same kind of functionality - but you probably need a fairly deep understanding of I2C before you start. That's kind of the point of using pre-written driver code. So you don't have to be an expert on every last detail just to be able to set the RTC or read the temperature sensor or whatever it is. In a very Arudino like way, using driver code like this gives you some trustworthy, prewritten driver code so you can just get on and design your RTC/temp/whatever based device and leave the details of what's really going on with the SDA/SCL wires to someone else to worry about.

Ok, I'm willing to give a try to Peter's libraries and test code!

What is the '.S'? I'm using a Makefile. Is that a source code file or an header file?

YOU probably will not need the .s file.  Thats for Assembly programming.  Just use the .c and .h files and make sure you specify the SCL frequency AND the F_CPU frequency otherwise you will be very disappointed

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:

YOU probably will not need the .s file.  Thats for Assembly programming.  Just use the .c and .h files and make sure you specify the SCL frequency AND the F_CPU frequency otherwise you will be very disappointed

Jim

Ok... The F_CPU and SCL_CLOCK are already set. I set them to F_CPU 16000000UL and SCL_CLOCK 400000L. But I'm also not sure about the 400KHz. The datasheet says frequencies up to 400KHz max and 100KHz for voltages beloy 2.5V. So is this a choice of ours?

Edited;

Don't I also need to change the ports where SDA and SCL lines are connected to in any of the project files?

Last Edited: Mon. Oct 31, 2016 - 07:03 PM

No.  THe library will take care of that for you.

For now I would run SCL at 100khz this way should something not work clock speed is removed from the list of suspects.  100khz works at all voltages

JIm

Edit,

I might take the chance at splitting this thread since you are going to work with a TWI library now.  No pin checking needed.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Ok...

Anyway, I might need to change a few more things... My memory device is a 24LC08B device. The code assusmes the usage of a 24C02. Is this irrelevant regarding the memory address that is being used by the default code?

Also, how the code kind of "auto-detects" the pins where I have connected SDA and SCL lines?

I have connected a LED to the 19th pin of AtMega. And after I upload the firmware, the LED turns ON permanently. I think this is a bad sign when I look to the main function code that lights ON all LEDs connected to PORTB of the uC, right?

Edited;

I'm also not being able to capture any signal on the scope where I have SDA and SCL pins connected! :s

Last Edited: Mon. Oct 31, 2016 - 07:24 PM

Code assumes NOTHING  That is there for the example code only.

I can look for the version I use later today.  I cannot remember if I left it there, or removed it.

PsySc0rpi0n wrote:
I have connected a LED to the 19th pin of AtMega. And after I upload the firmware, the LED turns ON permanently. I think this is a bad sign when I look to the main function code that lights ON all LEDs connected to PORTB of the uC, right?

Could be.  DEpends on whats written there.  Post MAIN and lets see.

PsySc0rpi0n wrote:
Edited; I'm also not being able to capture any signal on the scope where I have SDA and SCL pins connected! :s

Did you put a 4.7k resistor from each pin to Vcc like you are supposed to?

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:

Code assumes NOTHING  That is there for the example code only.

I can look for the version I use later today.  I cannot remember if I left it there, or removed it.

PsySc0rpi0n wrote:
I have connected a LED to the 19th pin of AtMega. And after I upload the firmware, the LED turns ON permanently. I think this is a bad sign when I look to the main function code that lights ON all LEDs connected to PORTB of the uC, right?

Could be.  DEpends on whats written there.  Post MAIN and lets see.

PsySc0rpi0n wrote:
Edited; I'm also not being able to capture any signal on the scope where I have SDA and SCL pins connected! :s

Did you put a 4.7k resistor from each pin to Vcc like you are supposed to?

JIm

This is the main code:

#include <avr/io.h>
#include "i2cmaster.h"

#define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet

int main(void){
unsigned char ret;

DDRB  = 0xff;                              // use all pins on port B for output
PORTB = 0xff;                              // (active low LED's )

i2c_init();                                // init I2C interface

/* write 0x75 to eeprom address 0x05 (Byte Write) */
ret = i2c_start(Dev24C02+I2C_WRITE);       // set device address and write mode
if ( ret ){
/* failed to issue start condition, possibly no device found */
i2c_stop();
PORTB=0x00;                            // activate all 8 LED to show error */
}else{
/* issuing start condition ok, device accessible */
i2c_write(0x05);                       // write address = 5
i2c_write(0x75);                       // ret=0 -> Ok, ret=1 -> no ACK
i2c_stop();                            // set stop conditon = release bus

/* write ok, read value back from eeprom address 0x05, wait until
the device is no longer busy from the previous write operation */
i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode
i2c_write(0x05);                        // write address = 5
i2c_stop();

PORTB = ~ret;                           // output byte on the LED's

/* write 0x70,0x71,072,073 to eeprom address 0x00..0x03 (Page Write),
wait until the device is no longer busy from the previous write operation */
i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode
i2c_write(0x00);                        // write start address = 0
i2c_write(0x70);                        // write data to address 0
i2c_write(0x71);                        //    "    "   "    "    1
i2c_write(0x72);                        //    "    "   "    "    2
i2c_write(0x74);                        //    "    "   "    "    3
i2c_stop();                             // set stop conditon = release bus

wait until the device is no longer busy from the previous write operation */
i2c_start_wait(Dev24C02+I2C_WRITE);      // set device address and write mode
i2c_write(0x00);                         // write address = 0
ret = i2c_readAck();                       //  "    "    "    "     "    1
ret = i2c_readAck();                       //  "    "    "    "     "    2
ret = i2c_readNak();                       //  "    "    "    "     "    3
i2c_stop();                              // set stop condition = release bus

PORTB = ~ret;                            // output byte on the LED's
}

for(;;);
}


Yes, I have a 4k7 ohm resistors between SDA and Vcc and SCL and Vcc.

jgmdesign wrote:
YOU probably will not need the .s file. Thats for Assembly programming.

Not entirely true. As the user manual says:

http://homepage.hispeed.ch/peter...

This I2c library is implemented as a compact assembler software implementation of the I2C protocol which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). Since the API for these two implementations is exactly the same, an application can be linked either against the software I2C implementation or the hardware I2C implementation.

So the idea is that if you use a micro that has TWI (basically a "mega") then you use twimaster.c and forget all about the .S file. But if you use some brain dead (and I don't mean just the brain dead ones!) tiny that has no real TWI then you use i2cmaster.S instead of the twimaster.c and it "bit bangs" I2C/TWI on GPIO lines to simulate SDA/SCL.

As this is a mega328P one would be using twimaster.c UNLESS you have already tied up those pins for something else and cannot use the real TWI unit in which case bit-bang is the only option.

It might be worth noting that you have no choice of what pins are used when using the hardware TWI - they are fixed. You only get to choose when using software bit-bang.

Ok, clawson...

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module i2cmaster.S to your target when using the software I2C implementation !

But I'm still thinking about the AtMega pins where I should connect the SDA and SCL lines of the external memory IC!

Last Edited: Mon. Oct 31, 2016 - 09:36 PM

Kartman wrote:
It might be worth noting that you have no choice of what pins are used when using the hardware TWI - they are fixed. You only get to choose when using software bit-bang.

And what pins are those on the AtMega??

That's why we have the datasheet. I could read this for you, but we don't know exactly what device you are using so it would be likely i'd give you wrong information. Just take a few minutes reading the relevant sections of the datasheet and you'll have your answer first hand.

(Edit) actually you did in the title :(
10seconds of googling atmega328 pinout
Tells me pins 27 & 28

Last Edited: Mon. Oct 31, 2016 - 09:57 PM

Kartman wrote:
That's why we have the datasheet. I could read this for you, but we don't know exactly what device you are using so it would be likely i'd give you wrong information. Just take a few minutes reading the relevant sections of the datasheet and you'll have your answer first hand.

If I'm asking is because I haven't found that information!

And I already said what I'm using, more than once, but I'll say once again:

I'm using AtMega328P-PU and a 24LC08B from Microchip!

It amazes me that you can't find fundamental information on one of the most widely used hobbyist microcontrollers known to man. Yes, I did correct my post before you responded.
Since you're using a mega328, all the questions you could possibly have, have been answered already.....a million times. All you need is to Google. Maybe I should write a sticky on "how to Google"?

Kartman wrote:
It amazes me that you can't find fundamental information on one of the most widely used hobbyist microcontrollers known to man. Yes, I did correct my post before you responded. Since you're using a mega328, all the questions you could possibly have, have been answered already.....a million times. All you need is to Google. Maybe I should write a sticky on "how to Google"?

I have the extended datasheet opened but in faact this is the first time I noticed that those pins were assigned to SDA ans SCL! :o

Last Edited: Mon. Oct 31, 2016 - 10:14 PM

Ok, so then what have you learned so far?

How do you have the LED that stays on connected to the port pin? And which port pin?

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

It's on PAGE 1?!? It's not exactly rocket science is it?

I see this:

#define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet

and this:

ret = i2c_start(Dev24C02+I2C_WRITE);       // set device address and write mode

in the test code... Does these lines of code needs to be changed according to the memory IC I'm using?

If you read the datasheet on your memory IC like I did you would know what needs to be done.  In fact I told you how to address the EEPROM in post #30, last sentence.

Before this goes any further, I think you should post a schematic of how you have everything connected first.  If that's wrong, then all the code in the world is not worth squat diddley.

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:

If you read the datasheet on your memory IC like I did you would know what needs to be done.  In fact I told you how to address the EEPROM in post #30, last sentence.

Before this goes any further, I think you should post a schematic of how you have everything connected first.  If that's wrong, then all the code in the world is not worth squat diddley.

JIm

I read your sentence. I'm just not sure what is or what could be "proper bank". I know that my IC has A0, A1 and A2 not connected internally.

I'm reading the datasheet of my IC at page 7.

The circuit I have is kind of this:

PsySc0rpi0n wrote:
I read your sentence. I'm just not sure what is or what could be "proper bank". I know that my IC has A0, A1 and A2 not connected internally.

Keep Reading.  It's in there.  Hint...I said Proper Bank.  THey call it Bank Select.  And you are correct, it's on page 7

Anyway I do not have any of your EEPROMS handy but I have a X2404P sitting here that I can configure to operate just like yours does so I set up a little project and got things working.

Since I am familiar with your setup from your other thread I elected to make some changes to the example program to better suit your set up.

1.  In the i2cmaster.h file I removed all of the references to the example code as it was commented out and hence confusing...so out it went.

2. in twimaster.c I changed the F_CPU to 16Mhz

3. In twimaster.c I changed SCL frequenct to 100khz

4. In the MEGA328_I2C_EEPROM file I changed the DEFINE for the device and its address to what you need for your part to work with the example.

5. In the MEGA328_I2C_EEPROM file I changed the value WRITTEN to the memory cells to something you can display on your setup

6. In the MEGA328_I2C_EEPROM file I changed the PORTB configuration to use only the lower 4 pins.  THe reason you were seeing one or two LED's come on and stay on is because they are used by the XTAL clock

7. in the MEGA328_I2C_EEPROM file I ADDED a PORTB = RET instruction and a DELAY to show the value from the reads of teh EEPROM.

All of these changes I made are noted in their respective files at the locations with a "//<-------jgmdesigns"  OR "<-------jgmdesigns" as a comment at the line of change.

The i2cmaster.h file:

#ifndef _I2CMASTER_H
#define _I2CMASTER_H
/*************************************************************************
* Title:    C include file for the I2C master interface
*           (i2cmaster.S or twimaster.c)
* Author:   Peter Fleury <pfleury@gmx.ch>
* File:     $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp$
* Software: AVR-GCC 4.x
* Target:   any AVR device
* Usage:    see Doxygen manual
**************************************************************************/

/**
@file
@defgroup pfleury_ic2master I2C Master library
@code #include <i2cmaster.h> @endcode

@brief I2C (TWI) Master Software Library

Basic routines for communicating with I2C slave devices. This single master
implementation is limited to one bus master on the I2C bus.

This I2c library is implemented as a compact assembler software implementation of the I2C protocol
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
Since the API for these two implementations is exactly the same, an application can be linked either against the
software I2C implementation or the hardware I2C implementation.

Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
i2cmaster.S to your target when using the software I2C implementation !

Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

@note
The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
to GNU assembler and AVR-GCC C call interface.
Replaced the incorrect quarter period delays found in AVR300 with
half period delays.

@author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury

*/

/**@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif

#include <avr/io.h>

/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */

/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE   0

/**
@brief initialize the I2C master interace. Need to be called only once
@return none
*/
extern void i2c_init(void);

/**
@brief Terminates the data transfer and releases the I2C bus
@return none
*/
extern void i2c_stop(void);

/**
@brief Issues a start condition and sends address and transfer direction

@retval   0   device accessible
@retval   1   failed to access device
*/
extern unsigned char i2c_start(unsigned char addr);

/**
@brief Issues a repeated start condition and sends address and transfer direction

@retval  0 device accessible
@retval  1 failed to access device
*/
extern unsigned char i2c_rep_start(unsigned char addr);

/**
@brief Issues a start condition and sends address and transfer direction

If device is busy, use ack polling to wait until device ready
@return   none
*/

/**
@brief Send one byte to I2C device
@param    data  byte to be transfered
@retval   0 write successful
@retval   1 write failed
*/
extern unsigned char i2c_write(unsigned char data);

/**
@brief    read one byte from the I2C device, request more data from device
@return   byte read from I2C device
*/

/**
@brief    read one byte from the I2C device, read is followed by a stop condition
@return   byte read from I2C device
*/

/**
@brief    read one byte from the I2C device

Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak

@param    ack 1 send ack, request more data from device<br>
0 send nak, read is followed by a stop condition
@return   byte read from I2C device
*/
extern unsigned char i2c_read(unsigned char ack);

/**@}*/
#endif


The twimaster.c file:

/*************************************************************************
* Title:    I2C master library using hardware TWI interface
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp$
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device with hardware TWI
* Usage:    API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>

#include "i2cmaster.h"

/* define CPU frequency in hz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 16000000UL		//<---jgmdesigns changed - F_CPU value
#endif

/* I2C clock in Hz */
#define SCL_CLOCK  100000L		//<---jgmdesigns changed - LOW SPEED CLOCK

/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

TWSR = 0;                         /* no prescaler */
TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */

}/* i2c_init */

/*************************************************************************
Issues a start condition and sends address and transfer direction.
return 0 = device accessible, 1= failed to access device
*************************************************************************/
{
uint8_t   twst;

// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

return 0;

}/* i2c_start */

/*************************************************************************
Issues a start condition and sends address and transfer direction.
If device is busy, use ack polling to wait until device is ready

Input:   address and transfer direction of I2C device
*************************************************************************/
{
uint8_t   twst;

while ( 1 )
{
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
{
/* device busy, send stop condition to terminate write operation */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));

continue;
}
//if( twst != TW_MT_SLA_ACK) return 1;
break;
}

}/* i2c_start_wait */

/*************************************************************************
Issues a repeated start condition and sends address and transfer direction

Input:   address and transfer direction of I2C device

Return:  0 device accessible
1 failed to access device
*************************************************************************/
{

}/* i2c_rep_start */

/*************************************************************************
Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));

}/* i2c_stop */

/*************************************************************************
Send one byte to I2C device

Input:    byte to be transfered
Return:   0 write successful
1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{
uint8_t   twst;

// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;

}/* i2c_write */

/*************************************************************************
Read one byte from the I2C device, request more data from device

Return:  byte read from I2C device
*************************************************************************/
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)))
;

return TWDR;

/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition

Return:  byte read from I2C device
*************************************************************************/
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)))
;

return TWDR;



And the main project file Mega328_I2C_EEPROM:

/*
* Mega328_I2C_EEPROM.c
*
* Created: 10/30/2016 10:44:51 PM
*  Author: jgmDESIGNS-Laptop
*/

#define F_CPU 16000000ul
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <avr/pgmspace.h>

#include "i2cmaster.h"

#define Dev_24LC08B  0xA0      // device address of EEPROM 24LC88, see datasheet	<---jgmdesigns changed device name and address for device - See datasheet

int main(void)
{

unsigned char ret;

DDRB  = 0x0f;                              // use LOWER pins on port B for output <---jgmdesigns changed PINS USED
PORTB = 0x0f;                              // (active HIGH LED's )	<---jgmdesigns changed to ACTIVE HIGH

i2c_init();                                // init I2C interface

/* write 0x75 to eeprom address 0x05 (Byte Write) */
ret = i2c_start(Dev_24LC08B+I2C_WRITE);       // set device address and write mode
if ( ret ) {
/* failed to issue start condition, possibly no device found */
i2c_stop();
PORTB=0x00;                            // activate all 8 LED to show error */
}else {
/* issuing start condition ok, device accessible */
i2c_write(0x05);                       // write address = 5
i2c_write(0x75);                       // ret=0 -> Ok, ret=1 -> no ACK
i2c_stop();                            // set stop conditon = release bus

/* write ok, read value back from eeprom address 0x05, wait until
the device is no longer busy from the previous write operation */
i2c_start_wait(Dev_24LC08B+I2C_WRITE);     // set device address and write mode
i2c_write(0x05);                        // write address = 5
i2c_stop();

PORTB = ~ret;                           // output byte on the LED's

/* write 0x70,0x71,072,073 to eeprom address 0x00..0x03 (Page Write),
wait until the device is no longer busy from the previous write operation */
i2c_start_wait(Dev_24LC08B+I2C_WRITE);     // set device address and write mode
i2c_write(0x00);                        // write start address = 0
i2c_write(0x01);                        // write data to address 0	<---jgmdesigns changed value for demo
i2c_write(0x02);                        //    "    "   "    "    1	<---jgmdesigns changed value for demo
i2c_write(0x04);                        //    "    "   "    "    2	<---jgmdesigns changed value for demo
i2c_write(0x08);                        //    "    "   "    "    3	<---jgmdesigns changed value for demo
i2c_stop();                             // set stop conditon = release bus

wait until the device is no longer busy from the previous write operation */
i2c_start_wait(Dev_24LC08B+I2C_WRITE);      // set device address and write mode
i2c_write(0x00);                         // write address = 0
PORTB = ret;		//<---jgmdesigns added output for display on LED's
_delay_ms(750);		//<---jgmdesigns changed - added delay for display on PORTB
ret = i2c_readAck();                       //  "    "    "    "     "    1
PORTB = ret;		//<---jgmdesigns added output for display on LED's
_delay_ms(750);		//<---jgmdesigns changed - added delay for display on PORTB
ret = i2c_readAck();                       //  "    "    "    "     "    2
PORTB = ret;		//<---jgmdesigns added output for display on LED's
_delay_ms(750);		//<---jgmdesigns changed - added delay for display on PORTB
ret = i2c_readNak();                       //  "    "    "    "     "    3
PORTB = ret;		//<---jgmdesigns added output for display on LED's
_delay_ms(750);		//<---jgmdesigns changed - added delay for display on PORTB
i2c_stop();                              // set stop condition = release bus

//<---jgmdesigns changed - removed last PORT B write
}

for(;;);
}


Attached is the complete project with HEX file.

You connect your LEDs to PORTB 0, 1, 2, 3 Active High.

Project has been tested on a Mega328 with an X2404P EEPROM using Studio6_2 and an STK600 with an Atmel ICE.

Jim

## Attachment(s):

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Do you have any decoupling capacitors?

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

jgmdesign wrote:
And you are correct, it's on page 7
My only gripe about page 7 is that it's not clear what the X=don't care bit should be set to. Why don't they simply show it as a fixed 0? I can't imagine anyone passing 1 in that position though I suppose the implication is that you could, which is why it is "don't care".

Brian Fairchild wrote:
Do you have any decoupling capacitors?

Well the OP did type:

PsySc0rpi0n wrote:
The circuit I have is kind of this:

If you look at the video of his circuit in the other thread you will understand.

clawson wrote:
My only gripe about page 7 is that it's not clear what the X=don't care bit should be set to.

"Don't care" is pretty straightforward.....At least to me.  "'Don't care" has been used in datasheets for decades.

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Brian Fairchild wrote:

Do you have any decoupling capacitors?

Yes, I have but probably I wouldn't need because I'm using power from my USB-to-Serial converter which should be smooth enough, I guess. But I always use decoupling caps!

clawson wrote:

jgmdesign wrote:
And you are correct, it's on page 7
My only gripe about page 7 is that it's not clear what the X=don't care bit should be set to. Why don't they simply show it as a fixed 0? I can't imagine anyone passing 1 in that position though I suppose the implication is that you could, which is why it is "don't care".

Are you also sceptical about those bits??? I'm also too but I always set them to 0 no matter what! If they say it's a "don't care" I do believe and always set them to 0.

jgmdesign wrote:

Brian Fairchild wrote:
Do you have any decoupling capacitors?

Well the OP did type:

PsySc0rpi0n wrote:
The circuit I have is kind of this:

If you look at the video of his circuit in the other thread you will understand.

clawson wrote:
My only gripe about page 7 is that it's not clear what the X=don't care bit should be set to.

"Don't care" is pretty straightforward.....At least to me.  "'Don't care" has been used in datasheets for decades.

JIm

Although I haven't placed any decoupling caps on the schematic I placed here, I indeed have one 10uF (35V) cap between (+) and (-) lines!

jimdesigns, I'm going to write another post about the code you wrote because I have some questions about it!

0.1uF caps perform better as decoupling caps. Sprinkle a few across your supply lines... especially close to the chip's supply pins... and each of them even if there are two or three on each package.

Ross McKenzie, Melbourne Australia

valusoft wrote:
0.1uF caps perform better as decoupling caps
+1

The 10uF is a good bulk cap, but not as good for fast transients...

David

I'm still writing the post about jgmdesign code but I'll answer to these latest posts. The smallest polarised caps I have is 1uF. Lower caps are film caps. Not sure if they are good for decoupling purposes...

What size film caps?  Unless they are in the picofarad range you can use them....something is better than nothing.

Cannot wait to see this post you are writing....getting a little nervous.

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

jgmdesign wrote:

What size film caps?  Inless they are in the picofarad range you can use them....something is better than nothing.

Cannot wait to see this post you are writing....getting a little nervous.

JIm

I have a .01M and a 100n film caps... But I said I have a 10uF 35V decoupling cap... I didn't said I had none! ;) I also have a 1uF 50V cap here! Is this one better?

The reason that the post is taking so much time is because I went to have lunch in the meantime! :)

This pic is from AVR042 app note, note the use of "bypass" 100n caps on all (a)vcc/gnd pairs of pins.  Your avr will only have one or two pairs of pins, but all of them need 100nf caps as shown.  Download this app note, it has lots of good info, and explains why these caps are needed in addition to the one(s) you already have.

FF = PI > S.E.T

jgmdesign wrote:

PsySc0rpi0n wrote:
I read your sentence. I'm just not sure what is or what could be "proper bank". I know that my IC has A0, A1 and A2 not connected internally.

Keep Reading.  It's in there.  Hint...I said Proper Bank.  THey call it Bank Select.  And you are correct, it's on page 7

Anyway I do not have any of your EEPROMS handy but I have a X2404P sitting here that I can configure to operate just like yours does so I set up a little project and got things working.

Since I am familiar with your setup from your other thread I elected to make some changes to the example program to better suit your set up.

1.  In the i2cmaster.h file I removed all of the references to the example code as it was commented out and hence confusing...so out it went.

2. in twimaster.c I changed the F_CPU to 16Mhz

3. In twimaster.c I changed SCL frequenct to 100khz

4. In the MEGA328_I2C_EEPROM file I changed the DEFINE for the device and its address to what you need for your part to work with the example.

5. In the MEGA328_I2C_EEPROM file I changed the value WRITTEN to the memory cells to something you can display on your setup

6. In the MEGA328_I2C_EEPROM file I changed the PORTB configuration to use only the lower 4 pins.  THe reason you were seeing one or two LED's come on and stay on is because they are used by the XTAL clock

7. in the MEGA328_I2C_EEPROM file I ADDED a PORTB = RET instruction and a DELAY to show the value from the reads of teh EEPROM.

All of these changes I made are noted in their respective files at the locations with a "//<-------jgmdesigns"  OR "<-------jgmdesigns" as a comment at the line of change.

[I removed the code to make the post smaller]

...

...

...

Attached is the complete project with HEX file.

You connect your LEDs to PORTB 0, 1, 2, 3 Active High.

Project has been tested on a Mega328 with an X2404P EEPROM using Studio6_2 and an STK600 with an Atmel ICE.

Jim

I have downloaded your code just to make sure I was changing the correct lines in the original code!

The fisrt 4 points of your "todo list" I also did them! 1, 2, 3 and 4.

I changed the line:

#define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet

to this:

#define Dev24LC08B  0xA0      // device address of EEPROM 24C02, see datasheet

If I understood correctly, the Block Address value, is a 3 bit value in which the MSB of these 3 bit, is a "don't care" bit! This leaves me with 2 bits to select a Block Address. If I ignore the "don't care" bit I have 4 possible Block Addresses, correct? 00, 01, 10 and 11.

Another thing is that datasheet says:

The next three bits of the control byte are the block-select bits (B2, B1, B0). B2 is a “don’t care” for the 24XX08. They are used by the master device to select which of the four 256 word-blocks of memory are to be accessed.

I'm having some issues to understand this sentence!

There are 4 blocks of 256 words. Does this means that each block has 256 words and so, there will be a total of 1024 words (4 x 256) ???

Another question is what size has each of those 256 words? If the IC as 8k bytes of memory, means 8192 bytes... How does this relates to the 256 words per block of the 4 block the IC has? I would say that 8192 divided by 1024 (1 byte) equals to 8 bytes! Is this the size of each word?

Then in main function I have several questions:

1 -

/* write 0x75 to eeprom address 0x05 (Byte Write) */
ret = i2c_start(Dev_24LC08B+I2C_WRITE);       // set device address and write mode

The comment on this piece of code, says that we are going to write the value 0x75 to  address 0x05 of the IC?

Is this action taken in 1 step (1 line of code) or in more steps (more than one line of code)???

In the "else" statement in the main function you have:

i2c_write(0x05);                       // write address = 5
i2c_write(0x75);                       // ret=0 -> Ok, ret=1 -> no ACK

I don't understand how the same function sets the "place" where we are going to write and actually writes there the data we want!

Also, what is the 'ret' is saving and what for is that value used for? Ok I know it saves the return of the i2c_start() function, but what means thar value? (this question and almost all the others is result of me not using my own code, I don't know how things are working - that's why I always try to do my own stuff).

Then we have this:

/* write ok, read value back from eeprom address 0x05, wait until
the device is no longer busy from the previous write operation */
i2c_start_wait(Dev_24LC08B+I2C_WRITE); // set device address and write mode
i2c_write(0x05);                       // write address = 5
i2c_stop();


So, this suggests we have writen the value 0x75 at adress 0x05 and now we are going to read it back from the same address (0x05)

But why are we "waiting" in the first line of code and we send the same parameter as we did in the previous block of code and why are we sending a I2C_WRITE when we pretend to READ? And the comment says explicitly "write mode"???

And why are we using the function i2c_write() to specify the memory address where from we should read the previous written value of 0x75??? This is confusing and the comments are not intuitive!

Then we use a function i2c_rep_start() that is a supposed "repeated start condition" and we send a parameter that was sent before in the previous block of code? I mean, in the previous block of code, we firstly sent the device address and write mode and only after that we specified the memory address where to write the 0x75 value. In this piece of code we are sending first the memory address where we want to read and only after that we are sending the device memory address and write mode and again here we are using "write mode" when we are going to read! This looks like a paradox to me!

Then another thing that I cannot fully understand is that the ACK bit is a bit that should tells us if the write process has gone smoothly and has ended. So what are the functions i2c_ReadAck() i2c_ReadNack means? Couldn't it be a single function that would return 1 if there was an error or return 0 if the bit was read/written ok??? And why is the comment of the line code "ret = i2c_readNack()" "read one byte"??? Shouldn't this comment be something like "read the ACK bit state" or so???

Ok, I'm going to end this post here... But I'll apply the same questions to the rest of the code! Sorry if I'm not getting the point of the comments and the name of the functions used!

PsySc0rpi0n wrote:
If I understood correctly, the Block Address value, is a 3 bit value in which the MSB of these 3 bit, is a "don't care" bit! This leaves me with 2 bits to select a Block Address. If I ignore the "don't care" bit I have 4 possible Block Addresses, correct? 00, 01, 10 and 11.
Say you have block number 0, 1, 2, 3. The datasheet says:

So, yes the top nibble is going to 0xA?. As the 00/01/10/11 block bits are at position 1 this means the 4 block values are A0, A2, A4 and A6. Those are for read. Add 1 for write so A1, A4, A5 and A7. In reality you would likely create the address with:

addr = 0xA0 + (block_num << 1) + read_write_flag;

Say block_num is 3 (0b11) and the read_write_flag is 1 (meaning write) then this would be:

addr = 0xA0 + (0b11 << 1) + 1;

in which

(0b11 << 1)

is 6. So this comes out as:

addr = 0xA0 + 6 + 1;

so

addr = 0xA7;

PS forgot to say that if you only ever use:

ret = i2c_start(Dev_24LC08B+I2C_WRITE)

and Dev_24LC08B is defined as 0xA0 this can only ever be 0xA0 or 0xA1 so it only reads/writes block 0. That's why the addition of:

+ (block_num << 1)

is required.

Last Edited: Tue. Nov 1, 2016 - 04:20 PM

clawson, I just didn't understood the A0, A2, A4 and A6. I think I would need to see a possible graphic representation of the memory mapping of these kind of devices so that I could understand better these addressing issues. Can I think of it like if 4 layers of memory and in each layer there are 256 words of 8 bytes per word???

____________________________________________________________________

00-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

01-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

02-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

03-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

04-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

05-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

06-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

07-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

08-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

09-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

10-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

11-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

12-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

13-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

14-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

15-/00W/01W/02W/03W/04W/05W/06W/07W/08W/09W/10W/11W/12W/13W/14W/15W/

This would be 1 of the 4 banks. A 16 x 16 matrix where would be the 256 words of 8 bytes each to make the 8K memory total!

And there were 3 more banks like this!

Could it be pictured like this???

PsySc0rpi0n wrote:
I have downloaded your code just to make sure I was changing the correct lines in the original code!

I am guessing you went and manually made the changes instead of just using my source because you wanted to.

PsySc0rpi0n wrote:
I changed the line: #define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet to this: #define Dev24LC08B 0xA0 // device address of EEPROM 24C02, see datasheet

I should have mentioned that you will also need to change EVERY location in the main code where you see the old Dev24C02 to Dev24LC08B otherwise you will get an error at compile time.

PsySc0rpi0n wrote:
There are 4 blocks of 256 words. Does this means that each block has 256 words and so, there will be a total of 1024 words (4 x 256) ???

Correct.

PsySc0rpi0n wrote:
Another question is what size has each of those 256 words? If the IC as 8k bytes of memory, means 8192 bytes... How does this relates to the 256 words per block of the 4 block the IC has? I would say that 8192 divided by 1024 (1 byte) equals to 8 bytes! Is this the size of each word?

It is an 8K BIT not BYTE EEPROM, so 256 x8 = 2048 bits.  4 x 2048 = 8192 bits, or 1024 BYTES

PsySc0rpi0n wrote:

This confused me as well, and IMO is not something you need to worry about.  It can be removed as far as I can tell.  I just left it as it was a no harm, no foul.  I guess I should have removed it for you.

PsySc0rpi0n wrote:
But why are we "waiting" in the first line of code and we send the same parameter as we did in the previous block of code and why are we sending a I2C_WRITE when we pretend to READ?

We are not 'pretending' anything.  The comment says to wait for the previous WRITE to finish first, so...WAIT.  THEN READ.

PsySc0rpi0n wrote:
And why are we using the function i2c_write() to specify the memory address where from we should read the previous written value of 0x75???

You do an I2C_WRITE to set the base address of where you want to READ from.  As I just wrote, the write of 0x75 to location 5 should have been omitted by me.  Forget about it...if you can.

PsySc0rpi0n wrote:
This is confusing and the comments are not intuitive!

I disagree with you.  The comments are pretty self explanatory and if you go to Peter FLeurys website there is an Oline MAnual that explains this even further:

http://homepage.hispeed.ch/peter...

PsySc0rpi0n wrote:
Then another thing that I cannot fully understand is that the ACK bit is a bit that should tells us if the write process has gone smoothly and has ended. So what are the functions i2c_ReadAck() i2c_ReadNack means?

If you read teh Online manual you will find that I2CReadACK() is for reading multiple bytes sequentially as the code does and the I2C)ReadNak() is to read one single byte which the code does at the very end.

PsySc0rpi0n wrote:
Couldn't it be a single function that would return 1 if there was an error or return 0 if the bit was read/written ok??? And why is the comment of the line code "ret = i2c_readNack()" "read one byte"??? Shouldn't this comment be something like "read the ACK bit state" or so???

No, and I explained why one paragraph up.

PsySc0rpi0n wrote:
But I'll apply the same questions to the rest of the code! Sorry if I'm not getting the point of the comments and the name of the functions used!

Read the documentation in the Online Manual.

But I am going to ask WHICH comments are you having trouble with?  Peter's or Mine?

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

PsySc0rpi0n wrote:
clawson, I just didn't understood the A0, A2, A4 and A6. I think I would need to see a possible graphic representation of the memory mapping of these kind of devices so that I could understand better these addressing issues. Can I think of it like if 4 layers of memory and in each layer there are 256 words of 8 bytes per word???

That device says it is an 8Kbit memory. That is 1Kbyte of memory (the correct term is KibiByte but let's not get bogged down in semantics). The 1024 bytes are accessed as 4 banks of 256bytes.

So let's say you want to access the 687th byte of the 1024 available. Well 687/256 is 2. So this location is somewhere in block 2 (counting the 4 blocks as 0,1,2,3). In fact it is the 175th byte in block 2. (that is offset 0xAF). So say I wanted to write it I would start by addressing the device and block number as 0xA0 and block=2 and because it is a write the write_bit=1. So the high part of the address is 0xA0 + (2 << 1) + 1. That is 0xA0 + 4 +1 = 0xA5. So the i2c_start() would specify 0xA5. Then the address byte that follows that picks some offset in that 256 bytes would be the 0xAF meaning the 175th byte in block .

More generally:

uint16_t byte_num = 687; // for example
uint8_t block_num = byte_num / 256; // so 2 in this case
i2c_start(0xA0 + (block_num << 1) + read_write);
i2c_write(byte_num % 256)

byte_num could be any value from 0..1023 to access any one of the 1024 bytes.

Cliff:

clawson wrote:
and because it is a write the write_bit=1.

The WRITE bit is a 0, not a 1.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

clawson wrote:
That device says it is an 8Kbit memory. That is 1Kbyte of memory (the correct term is KibiByte but let's not get bogged down in semantics). The 1024 bytes are accessed as 4 banks of 256bytes.

Why bother going through all this for 1KB when the device already has 1KB of byte-addressable EEPROM on board?

I've totally lost how this applies to "reading value from pin", so I'll crawl back into my lair. [drifted off topic - I'll do something with the title]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Tue. Nov 1, 2016 - 06:02 PM

theusch wrote:
Why bother going through all this for 1KB when the device already has 1KB of byte-addressable EEPROM on board?

+1

(though my guess is that this is the classic error of reading 8Kb as 8KB. It can come as something of a disappointment to find you have 1/8th the memory you thought you were getting! ;-)

jgmdesign wrote:

I am guessing you went and manually made the changes instead of just using my source because you wanted to.

I was already doing it before you post your code... Obviously I was not absolutely sure of what I was changing. But at least a few things are the same as in your code!

jgmdesign wrote:

I should have mentioned that you will also need to change EVERY location in the main code where you see the old Dev24C02 to Dev24LC08B otherwise you will get an error at compile time.

And yes I also changed all the occurrences of the old macro name to the new one.

Well, maybe it's me but the comments confuses me! the function names are counter intuitive! This is why I always like to write my own code!

Why the functions are not something lile:

i2c_init()

i2c_writeByte()

i2c_startBit()

i2c_stopBit()

i2c_checkACK()

I'm not sure if these would be enough to the whole I2C process, but I think these names are a lot more intuitive than the ones used!

I simply cannot understand some of the points that I stated in my post #63 that were not addressed! And to read and understand the online Peter Fleury's manual, I should know exactly what are each and every registers used in his code. I'll name them:

TWSR

TWBR

TWCR

TWINT

TWSTA

TWEN

TW_STATUS

TW_START

TW_REP_START

TWDR

TW_MT_SLA_ACK

TW_MR_SLA_ACK

TW_MR_DATA_NACK

TWSTO

TW_MT_DATA_ACK

TWEA

I cannot understand Peter's code if I don't know what are each of these registers and what they do/control!

Well, I guess if one wanted to experiment with I2C and had this device lying about, it would be a good place to start.  Or maybe RTC such as DS1307.  But why would one have these lying about nowadays?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

PsySc0rpi0n wrote:
, I should know exactly what are each and every registers used in his code.
You do own a copy of the 328 datahseet don't you? As I think I pointed out previously:

That is the from the "Register Summary" table towards the end of the document. If you click on any of the blue links there it takes you to the likes of:

That was what I saw when I clicked through on TWCR.

Using:

http://www.atmel.com/Images/Atme...

The things you list are documented as follows:

TWSR - page 293

TWBR - page 292

TWCR - page 296

TWINT - (a bit within TWCR so also on) page 296

TWSTA - (a bit within TWCR so also on) page 296

TWEN - (a bit within TWCR spills over onto) page 296

TW_STATUS - this comes form the compiler's headers. Fleury includes <compat/twi.h> and that in turn includes  <util/twi.h>

C:\SysGCC\avr\avr\include\util>grep TW_STATUS twi.h
* \def TW_STATUS
#define TW_STATUS               (TWSR & TW_STATUS_MASK)

TW_START

C:\SysGCC\avr\avr\include\util>grep TW_START twi.h
\def TW_START
#define TW_START                0x08

TW_REP_START

C:\SysGCC\avr\avr\include\util>grep TW_REP_START twi.h
\def TW_REP_START
#define TW_REP_START            0x10

TWDR - page 295

TW_MT_SLA_ACK - see the following

TW_MR_SLA_ACK - see the following

TW_MR_DATA_NACK - see the following

TW_MT_DATA_ACK - see the following...

C:\SysGCC\avr\avr\include\util>grep _ACK twi.h
\def TW_MT_SLA_ACK
#define TW_MT_SLA_ACK           0x18
\def TW_MT_DATA_ACK
#define TW_MT_DATA_ACK          0x28
\def TW_MR_SLA_ACK
#define TW_MR_SLA_ACK           0x40
\def TW_MR_DATA_ACK
#define TW_MR_DATA_ACK          0x50
\def TW_ST_SLA_ACK
#define TW_ST_SLA_ACK           0xA8
\def TW_ST_ARB_LOST_SLA_ACK
#define TW_ST_ARB_LOST_SLA_ACK  0xB0
\def TW_ST_DATA_ACK
#define TW_ST_DATA_ACK          0xB8
\def TW_SR_SLA_ACK
#define TW_SR_SLA_ACK           0x60
\def TW_SR_ARB_LOST_SLA_ACK
#define TW_SR_ARB_LOST_SLA_ACK  0x68
\def TW_SR_GCALL_ACK
#define TW_SR_GCALL_ACK         0x70
\def TW_SR_ARB_LOST_GCALL_ACK
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
\def TW_SR_DATA_ACK
#define TW_SR_DATA_ACK          0x80
\def TW_SR_GCALL_DATA_ACK
#define TW_SR_GCALL_DATA_ACK    0x90

TWSTO - (a bit within TWCR so also on) page 296

TWEA - (a bit within TWCR so also on) page 296

To be honest there aren't that many places you need to look. If they any such symbol appears in the Fleury code it's either a symbol he's created or it's coming from a header file. The only headers you have to explore are:

#include <inttypes.h>
#include <compat/twi.h>

#include <i2cmaster.h>


and in turn:

#include <avr/io.h>


If you don't find the symbols in Peter's local headers then they must be in the compiler/C library headers. As I say <util/twi.h> is fairly key to all this. There is some documentation for it in the compiler user manual:

http://www.nongnu.org/avr-libc/u...

PS one slight gripe I have with the Fleury code is that he does not make the correct use of <> and "" in #include statements. For his own headers he should be using "" not <> so, for example:

#include <inttypes.h>
#include <compat/twi.h>

#include "i2cmaster.h"

that would instantly tell you that the top 2 come from the compiler/C library while the latter is local to the Fleury code. Also C compilers have different search paths for <> (system headers) versus "" (user headers) so it is important to use the right one.

Last Edited: Tue. Nov 1, 2016 - 06:30 PM

theusch wrote:

clawson wrote:
That device says it is an 8Kbit memory. That is 1Kbyte of memory (the correct term is KibiByte but let's not get bogged down in semantics). The 1024 bytes are accessed as 4 banks of 256bytes.

Why bother going through all this for 1KB when the device already has 1KB of byte-addressable EEPROM on board?

I've totally lost how this applies to "reading value from pin", so I'll crawl back into my lair. [drifted off topic - I'll do something with the title]

Indeed... If I can change the title myself, I'll change it to something like "I2C Peter Fleury's library questions" or so...

clawson wrote:

theusch wrote:
Why bother going through all this for 1KB when the device already has 1KB of byte-addressable EEPROM on board?

+1

(though my guess is that this is the classic error of reading 8Kb as 8KB. It can come as something of a disappointment to find you have 1/8th the memory you thought you were getting! ;-)

Yes, it is usual that 8K is assumed to be 8K bytes... I don't mind, at this point that I have 1/8t of what thought to have! I just need/want to understand this! And in the datasheet I have, there's no reference to 8K bit nor 8k byte... Just 8k...

PsySc0rpi0n wrote:
there's no reference to 8K bit nor 8k byte... Just 8k...
Err no...

From Page 1.

For readers used to these things (most memory devices are specified in bit rather than byte capacity as it makes no assumption about the width you will use to access it) then the "8k-bit"stands out like a sore thumb.

It then goes onto say 4 blocks of 256 8bit locations. That is 4 lots of 256 bytes which is a grand total of 1024 bytes.

Arrgghhh... I search the document by "8kbit". It didn't found any match... Of course, it was "8 Kbit"... There was a space and a capital 'K' that i didn't include in the search!

PsySc0rpi0n wrote:

Arrgghhh... I search the document by "8kbit". It didn't found any match... Of course, it was "8 Kbit"... There was a space and a capital 'K' that i didn't include in the search!

If you are trolling, you are doing an excellent job of it.

Earlier, it seemed that no search was done in the AVR datasheet for SCL or SDA.  Now, the TWI chapter doesn't come right out and give a pin assignment table, but as pointed out it can be seen in Pin Configurations and explained in Alternate Functions of Port C.  So I can see where reading the datasheet might miss it.

Now it seems you are a convert to searching, and skipping the reading part.  Like the first page of the EEPROM datasheet Description: paragraph.  I assume you got these devices from somewhere, like DigiKey.  I read there:

Reading is also involved when using e.g. Fleury code.  What does the first page of description say?

Detailed Description

I2C (TWI) Master Software Library.

#include <i2cmaster.h>

Basic routines for communicating with I2C slave devices. This single master implementation is limited to one bus master on the I2C bus.

This I2c library is implemented as a compact assembler software implementation of the I2C protocol which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). Since the API for these two implementations is exactly the same, an application can be linked either against the software I2C implementation or the hardware I2C implementation.

Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module i2cmaster.S to your target when using the software I2C implementation !

Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

Note

The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted to GNU assembler and AVR-GCC C call interface. Replaced the incorrect quarter period delays found in AVR300 with half period delays.

Author

Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury

(C) 2015 Peter Fleury, GNU General Public License Version 3

API Usage Example

The following code shows typical usage of this library, see example test_i2cmaster.c

#include <i2cmaster.h>

#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet

int main(void)

Did you study or use the worked example?  If I had to guess 2402 code might even work unmodified for 2408.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

PsySc0rpi0n wrote:
And to read and understand the online Peter Fleury's manual, I should know exactly what are each and every registers used in his code. I'll name them:

The read the bloody datasheet like the rest of us do!

For someone that says they want to learn, you sure can throw a lot of crap back at the people that are in fact trying very patiently to help you...again!

I spent quite a bit of time last night making sure that code worked according to your setup.  And I also told you why the LED's were coming on and staying on because of the crystal oscillator...  Rather than bitch at me, and the others here, I would think that you would have run loaded the HEX file I provided, and confirmed what I wrote should happen with the LED's so you know the code is working...THEN start to dissect what was happening in the code itself.  BUT theres nothing in any of your posts that says you have done this.

I'll repeat what was said to you in your other thread....STOP fighting something that works.  See that it works so you have something to reference off of, THEN dissect it.  HAd you run the code I sent, you could modify the four data bytes I used (0x01, 0x02, 0x04, 0x08) with anything between 0x00 and 0xfF to see that the code indeed works.  YOu then go back and walk through the code and look at what registers are used in each function.  They are clearly seen in each function in the twimaster.c file.

I thought wrong all the way around on this one.

All the best on your quest.

theusch wrote:
so I'll crawl back into my lair.

Got any more room in there?  I'll bring some ribs for the BBQ

Jim

Edit:

@Lee:

Did you study or use the worked example?  If I had to guess 2402 code might even work unmodified for 2408.

I uploaded a project with HEX file last night for him to simply load into the AVR and it should work

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

"The critical shortage here is not stuff, but time." - Johan Ekdahl

"Step N is required before you can do step N+1!" - ka7ehk

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Tue. Nov 1, 2016 - 07:41 PM

theusch wrote:

PsySc0rpi0n wrote:

Arrgghhh... I search the document by "8kbit". It didn't found any match... Of course, it was "8 Kbit"... There was a space and a capital 'K' that i didn't include in the search!

If you are trolling, you are doing an excellent job of it.

Earlier, it seemed that no search was done in the AVR datasheet for SCL or SDA.  Now, the TWI chapter doesn't come right out and give a pin assignment table, but as pointed out it can be seen in Pin Configurations and explained in Alternate Functions of Port C.  So I can see where reading the datasheet might miss it.

Now it seems you are a convert to searching, and skipping the reading part.  Like the first page of the EEPROM datasheet Description: paragraph.  I assume you got these devices from somewhere, like DigiKey.  I read there: