NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Project Help and Ideas » External EEPROM Page Write - 24LC512
June 21, 2013 by dvdsnyd |
Hi all, I have been playing around with an external EEPROM. I am using an I2C based Microchip 24LC512. There is quite a bit of good documentation on how to communicate with the device and to read and write one byte of data. One byte of data takes about 5 ms to write, as opposed to using the 128 byte internal page buffer, it takes about 5 ms to write up to 128 bytes using a "Page Write" routine. I am having difficulty getting started implementing a page write routine for a data logger. I would like to be able to log time in ms and pressure/altitude in a comma delimited format. Essentially take the readings from a BMP085 pressure sensor and log them against time for a rocket altimeter. Where I am having difficulty is how to achieve this. The pressure is a long data type, time is also a long data type. How should I go about preparing the data to be sent to the EEPROM? Break down the long data types into bytes - msb,lsb,xlsb type format? Or convert everything to a string and concatenate it all into one long "word" and send it all? If someone could help me get over this hump, I think I have a lot of it figured out. Thanks as always! Please let me know if I need to elaborate on something. Dave |
---|---|
June 21, 2013 by dvdsnyd |
Hi again, I have looked at Noter's thread a bit, he is using pointers and structures. Doing it that way, does it eliminate the need for strings and conversion because it is using the address location? Just trying to make sense of it all... Thanks Dave |
June 21, 2013 by Noter |
I think using a structure is the easiest way to move multiple data fields at once. I typically use a pointer out of habit but it's not absolutely necessary. Use a typedef to define your structure:
Then use it to allocate some ram:
And, pass the address of the structure in ram to your fuctions that read or write data from eeprom:
or
If you're not using a pointer you reference the structure fields with a "." instead of "->".
It all gets easier with a little practice. |
June 22, 2013 by dvdsnyd |
Noter, I am going to read through the links that you posted on your EEPROM thread on points and structures today. That might clear some stuff up. However, a couple of questions: Could you explain this statement a little more? Then use it to allocate some ram: LOG_DATA rocket_altimeter; What is rocket_altimeter? Is it a declared variable with a certain amount of bytes data storage? Also, when you are passing the data into write_eeprom_data, the second parameter being passed is:
Is this the size of the data that is going to be written to the eeprom? Thanks again Noter, I really appreciate your explanations. They are always helpful! Dave |
June 22, 2013 by dvdsnyd |
I just googled "sizeof c" and I think I answered my second question. It is indeed the size of the data in bytes. I guess, now I am curious how the write_eeprom_data handles the splitting up of the the data into the bytes...Maybe this is unnecessary since we are using the structs? |
June 22, 2013 by Noter |
Just as "int counter;" allocates 2 bytes of ram for the variable named counter, "LOG_DATA rocket_altimeter;" allocates sizeof(LOG_DATA) bytes of ram for the variable named rocket_altimeter which happens to be a structure instead of an integer. Be sure to read the section on typedef's for a better understanding of defining your own data types in C. |
June 23, 2013 by dvdsnyd |
Noter, I read through the online "book" on the C programming language that you reference. There is a lot of good information within it. I wish it was laid out a little better, but it is really well written. Good balance for anyone getting started in C or anyone who has been dabbling in it for a while, looking to expand...Anyways, I think I am starting to get a grasp on pointers and structures. In your original code, you write a block of data to address 0x0000. Does all of the data go to that address? I can't imagine it does because each address cell is only one byte long. How does this work? The way I understand eeprom, is you can only write one byte at a time or you can write up to a full page at a once. Thanks, Dave |
June 23, 2013 by Noter |
The original code is using page write which can write up to the page size of 64 bytes. Just give a starting address followed by 2 to 64 bytes of data in a single I2C/TWI transmission and you're in page mode. Be careful not to write past device boundaries but that's really only a consideration f you're using more than a single eeprom chip. |
June 28, 2013 by dvdsnyd |
Thanks Noter, I think I will be able to come up with some code to make efficient use of each page. Might have to split some writes near page boundaries into separate writes. I have the EEPROM hooked up to ehe microcontroller, and have very basic code - not using pointers and structs yet. I just wanted to see if I could get communication with it and write a few bytes of data and read them to the terminal, howver I have come to a snag. My program compiles, but it gets hung up on the first line of the following code chunk.
It is almost acting like it isn't even entering this code. Because I do not get a return message, however if I put a serial print after this code block, I don't get anything either. It is like it is frozen here. I am positive I have the correct device address. I even tried putting in 0x30 to see if it output a return, nothing. Anyone have any thoughts on this. I have never seen this behavior. I have worked with I2C before, so this isn't totally new territory for me. Any help is greatly appreciated! Thanks, Dave |
June 28, 2013 by pcbolt |
Dave - I think this is the source code for the function you are using...
Most likely you are getting hung up on line 20. This will effectively wait forever if there is no communication with the EEPROM module. You could test this by writing to the serial terminal before the "i2c_start()" call...something like
If you are stuck here, check to make sure you set up the clock correctly in "i2c_init()", then the usual suspects (wiring, power level, etc). |
June 28, 2013 by dvdsnyd |
pcbolt, Thanks for your reply and thoughts. You are indeed correct, I am using the Fleury I2C library. I have gotten it to work for my pressure sensor a few weeks back, so I was excited to start onto the next part...EEPROM :-) I do have a statement right before my i2c_start call. On the serial monitor I get the "waiting for start condition" , but like you are suggesting it is probably hanging up. Here is my twimaster.c file: I originally had the clock speed set to 300Khz - The datasheet says the chip can go up to 400Khz. I bumped it down, but nothing changed.
I am putting 5 volts from the USB port into the device. Some other things I tried...
For addressing, I have all of the chip select pins set to digital logic zero - all running to ground...which from the data sheet, the first 4 bits are 1010, then my three bits are 000...which gives 0b01010000 when adding the start bit...which = 0X50, I have seen others using this as well, Rick is using a very similar chip, and is using 0x50 - so I believe this is correct. Any other suggestions? Anything you need from me that would help troubleshooting this issue? Thanks again for all of your help and support! Dave |
June 28, 2013 by pcbolt |
Dave - Try using "0xA0" (0b1010 0000) instead of "0x50" (0b0101 0000). Sometimes the device code is listed as the highest 7-bits of the address sent out over the I2C line and the lowest bit is R/W. |
June 28, 2013 by dvdsnyd |
pcbolt That did it! changed that device address, and I am writing 245 to the EEPROM and am able to read 245 from it as well! Exactly what I am asking it to do! Working great! Thanks a lot! I don't know what I'd do without this forum. Now that I have my "primitive" code running, I need to try to figure out how to get points and structures working - seems that is the best way to write large amounts of data to the EEPROM. Then dealing with the page boundaries could be interesting. If anyone has any suggestions for an EEPROM data logger, let me know! Thanks again! Dave |
June 28, 2013 by pcbolt |
Dave - I think the easiest way to manage the EEPROM writes is to store a page worth (128 bytes) of data in a buffer inside your program. When it gets full you can dump the whole thing in one shot to the EEPROM. If I understand the datasheet correctly, the EEPROM does a full refresh of the entire page after each "i2c_stop()" it sees, so writing one byte at a time is almost the same as writing a page. Since your data records are 8 bytes (2 longs) you'll be able to store 16 records before offloading the page. This means you'll need to keep track of the record count and the page index. You're still left with the problem of how to convert your records into a byte stream to send to the EEPROM. There a quite a few ways to do this. You could do this "manually" like this...
This works but gets confusing and doesn't teach you anything about structures and pointers. Using Noter's structure above you can make this cleaner and even use an array of these stuctures to organize your data...
I'm pretty sure at this point both "data_buffer" arrays would be identical except for one thing...you can access every byte in the first array by using "data_buffer[1], data_buffer[2], etc". In the second case you can't directly access each byte because "data_buffer[1]" points to the 8th byte (zero-indexed) and "data_buffer[2]" points to the 16th byte. There's no way to ask for "data_buffer[1.25]". This is where pointers and casting come in. We can create a new variable that points to the same buffer but can access individual bytes...
|
June 30, 2013 by dvdsnyd |
Thanks again pcbolt! This is a great add on to what Noter had posted a few days ago. I like the idea of having a page buffer like you describe. I was thinking of doing 16 individual page writes instead of 1 page write. It makes much more sense to do what you are proposing. When I go to read the data, I will have to construct the individual bytes back into a long data string correct? Which means I would have to do the reverse of the first suggestion for writing data? Or can it all be done through structures and pointers too? I am trying to make sense of structs and pointers...I will get there. Thanks so much for your help! Dave |
July 09, 2013 by dvdsnyd |
pcbolt, I have been stumbling over the code you posted in my thread as well as others on the NK forums. I felt I had reached a point where I could finally write up some code and try it out. You can ignore the EEPROM Read and Write routines, they are not used in this example. I mainly wrote this to test out the struct and some of the pointer concepts. The output of this code to the PuTTY window is:
So, the first 4 bytes is the "time" corresponding to 100, and so on. The way it appears to be writing is LSB first, whereas your first method without a data structure, looks as though it is MSB first. Do you think this is caused by the way I am writing the data? One other question; I am a little confused with this piece of code:
The way I am understanding this, is my_byte_array = data_buffer points my_byte_array to address location of the first byte of data contained in the data_buffer, Then from there, each byte is written to either the EEPROM, or in my practice code, I have it writing to serial terminal. Is this how it works? I guess I was expecting the use of either an * or an & to accomplish this... I imagine that reading the EEPROM would be similar, I will choose how much data I want to receive - 128 bytes (1 page), read the data into the data_buffer struct. Will the struct put the bytes back together to form the long pressure and time words? Thanks for all of your help! Glad the forums are back! You all have been awesome! My practice code follows, below... Thanks! Dave
|
July 10, 2013 by dvdsnyd |
Hi again, I am trying to figure out how to read the EEPROM data in the form of the data buffer structure. Could I do something like?:
Thanks, Dave |
July 13, 2013 by pcbolt |
Hi David, Thought this site was a goner again and I haven't had a chance to test it in a while. Looks like your code is working correctly, even though the byte order "seems" to be reversed. I wasn't sure how the MCU stored 32-bit numbers but it looks like you're right the LSB gets stored first. It really isn't too important as long as you use the same method to read the data as you do when you write it. I guess if you needed to make the byte arrays identical using the "manual" method you could just re-arrange the code as follows...
For this question "I guess I was expecting the use of either an * or an & to accomplish this...", normally you do need to use * and/or & for single variables but arrays are different. The name of an array without the brackets is the address of the first element in that array so you don't need the '&' ("address of") operator. You also don't need the '*' ("value at address") operator to access the data, you just need to add the brackets. Here are some examples...
In your last post, you can't return an entire structure, but you can return the address of a structure. This will not make much sense since the address won't change. The best way to do this is to pass the address of a "LOG_DATA" structure as a parameter to the function like this...
Then when you need to call it you can use something like this...
Your function will change the contents of the array but not the address. I used a "void" return value as an example, in practice I might think about returning a success/error code. |
July 14, 2013 by dvdsnyd |
Hi pcbolt! Thanks for replying! I was thinking the site was gone again too...glad they got it back up - no news on why it went down or if the libraries will be brought back online though...anyways, on to the project at hand :-) I am still a little confused about pointers and arrays... Why, in the following example, did you not declare a pointer variable?
but, in this example(below), you did:
Also, why in the second example is my_byte_array, not an array? Should it read?:
Maybe I am making a mountain out of mole hills on all these small details, but unfortunately, I need to understand many of the tiny little details of something before I truly understand and am able to use it effectively... :-( One other thing, I am going to post "my code" below, I am using "*" and "&" to access the data, maybe I am doing this incorrectly, it seems to be working, however the more I read about c programming, the more I realize it is an open and free language, that will let you break the rules...Does what I am doing make sense or break any rules/a good way to do things? Here are the specific parts I am referring to... Note, I came about this way of doing it by trying to appease the compiler :-) It seems to be working, I read the same data that I am writing...but is it "proper?"
Thank you so much for your helpful advice! Dave
|
July 15, 2013 by pcbolt |
That should work. I thought the compiler might give a warning "mis-matched data types' or something like that, so this line...
should quiet the warnings since you explicitly cast the array to point to a "uint8_t". I wouldn't think you would need the '&' symbol since you are dealing with an array in this case. I would think this would work...
Now all you need to do is try and retrieve the 32-bit "pressure" and "time" values out of the byte array. You will want to make the right cast in this case like this...
If you pass "data_buffer" to your read_eeprom function it should work except you'd use the "data" buffer instead of "my_byte_array". |
July 15, 2013 by dvdsnyd |
pcbolt, Thanks for the explanation, I tried out:
and it is working. with regard to retrieving the 32-bit data values from the EEPROM, I have already declared:
However, you are saying to do this:
I am confused, for some reason I am thinking the above line of code is altering or interfering with the local declaration of my struct...I am probably thinking wrong, Is it creating a pointer somehow? I will tell you how I attempted to retrieve the data last night: However, it did not work... Maybe you can explain why...except I like the idea of passing a pointer to the struct to the eeprom read function - seems to be a more "all-in-one" approach...anyways: I declared the following:
And in my main routine:
Now, my eeprom_byte_read_seq() function
My plan was then to use the read_data variable and set it equal to data_buffer, similar to how we were using the my_byte_array, but "backwards" to get the data back into the struct form... It read data, and some of it corresponded to the correct written data, but it was acting like it wasn't picking up on the correct starting address, since some of what is retrieved is garbage. Thanks again! Between your excellent explanations and working through and trying things for myself, I am starting to slowly grasp pointers and structs...and the heart of C :-) I really appreciate you, and everyone taking the time to help with my projects! I hope one day I can return the favor! ..at the very least show you the fruits of your labor with a completed project, as promised over a year ago! Dave |
July 16, 2013 by pcbolt |
Dave - I think you're right, this won't work...
Line 1 allocates the memory to store 2 "LOG_DATA" type variables (or structures). The value of "data_buffer" with no brackets will store the address of the first structure. Line 2 re-assigns this address and the original memory location is allocated but can't be accessed anymore since the starting address is lost (it may not even compile). What we need to declare a "LOG_DATA" pointer...
Now we can set it's address to the beginning of the "my_byte_array"...
To access the individual parts of the structure you can use...
To get to the next structure just increment "p_logdata"...
The compiler will automatically increment the address by the size of the structure. |
July 16, 2013 by dvdsnyd |
pcbolt, Thanks for all your help! I just successfully wrote data structure to the EEPROM via the use of pointers, as well as read the data written the EEPROM using pointers to get it back in the structure format. I also verified that my read data was in fact being read from the EEPROM and not just the data structure I set up initially! I think my next step is to start figuring out a schematic an PCB layout for my altimeter testing platform. While I do this, I will be integrating the pressure sensor with the EEPROM. Dave |
September 16, 2013 by dvdsnyd |
Hi All! Hope you are all doing well! It has been a while again since I have posted anything, a quick update and a question too. I have prototyped my little altimeter board on protoboard with a stand alone ATmega 168, along with a BMP085 pressure sensor and the 24LC512K EEPROM, and a beeper. I will have to post a pic soon. On to the question: I have been working with the EEPROM now for a while, trying to get it to mesh with the pressure sensor. I have yet to try to actually send the EEPROM pressure data. I have been "simulating data" and trying to get it to read it back to me. This is not going well.. I have posted my code below. The main code in question lies between lines 119 and 158. There is a EEPROM Write structure sequence and an EEPROM read structure sequence. I am able to get the data read, however in the serial window, I am getting almost 60 pressure structure reads, instead of just 32 for each "page" I get 27 garbage structure reads, then the correct 32. Then it goes to the next page, I get garbage, then 32 good reads. I am confused, because I am only incrementing 32 times, why would I be getting more than that? Unless there is something I am not seeing in my logic? I have played around with it some, and gotten it to enter an almost never-ending loop. It doesn't make any sense... Any suggestions would be great! If you need any more specifics, I would be more than happy to post them, just ask. Also, if someone has a better way to do what I am trying to do, please let me know. I feel as though I am trying to do it in a long round about way... Thank you once again for all of your help! Dave
|
September 17, 2013 by dvdsnyd |
Hi all, I am still trying to wrap my head around my problem. Does what I say above make sense or do I need to try to explain it better? Any insight would be greatly helpful! Thanks, Dave |
September 17, 2013 by dvdsnyd |
OK, I thought I would try to clean up my hard to read code and give a serial print out of what I am seeing while running the code. First, here is the revised, hopefully easier to read code:
Now, here is the print out I see form the serial window when I run the above code, exactly.
A few things That I'd like to point out
Does anyone see anything in my code that would make this happen? Am I not using the structure properly? Thanks again for all of your help! Please let me know if I can help clarify things. Dave |
September 17, 2013 by pcbolt |
Dave - Try changing line 124 from:
To this:
I can't see how you're getting an odd number of false outputs (27?) very strange. |
September 18, 2013 by BobaMosfet |
dvdsnyd- Your struct has one field (in the above example). Use an array instead. Use unsigned longs. An array is consecutive if single-dimension, so no need to convert your array of longs into an array of bytes-- it's already an array of bytes. Just pass the address of the first element as a char* (cast/coerce it) when passing to your EEPROM write routine. For reading, do the same. The EEPROM routine doesn't care how you look at your RAM-- that's logic. All it cares is that there is a block of RAM of the right number of bytes, that it can read data into. BM |
September 18, 2013 by BobaMosfet |
dvdsnyd (and others)- There is no difference between a struct and any other type of variable. It is a myth to believe that base data types are in any way special or unique, or 'more powerful than any typedef variable you create yourself. They are not. The only difference between a struct and any non-aggregate type of variable is that the syntax associated is there so that the compiler knows how to access each field through offsets from the base address. It also will add padding bytes if necessary, depending on field length, in order to align fields in memory for faster access (unless this compiler option is off).
The above typedef if packed is 3 bytes in length. If unpacked, it's likely 4, because myChar will be followed by another byte so that myInt starts on an int/short boundary. It depends on architecture's native word size and a few other compiler settings as to how it's likely to pad. There are ways of controlling this, for cross-compiler and cross-platform issues-- but that's way beyond what we're discussing here. If (unpacked), we had an array of aggType, with specific values, it would look like this in RAM (The program first):
I've denoted the pad-byte as 'XX' above, but in truth it will be whatever value happened to be last at that byte in RAM. Could be zero, could be anything else. Doesn't matter, we never look at it. When the compiler references the fields in the struct, it calculates the address of the structure you reference (myArray[0] or myArray[1]) and then adds (+) an offset to the field in question. This is what the linker does. It links. Your variable is a symbol in the symbol table with offsets for the linker to each field. So in the above, &myArray[0] = 0x00000000. &myArray[1] = 00000004. The address of &myArray[1].myInt = 00000004+2 (address + offset). But in looking at the above, you can see that the array of structs is a consecutive set of bytes. You could pass it to any block device (disk, ram card, etc) as simply (using an imaginery driver function 'WriteDevice'):
It will treat the block as array of unsigned bytes, because that's what we told the compiler to address it as, when calling the function. 'Nuff for now, I have to get other things done. Hope that helps. Any mistakes, I blame my lack of coffee this morning. :P BM |
September 18, 2013 by Noter |
Dave, I couldn't see anything in your code that could cause the error and I had a external eeprom already setup on a breadboard so I gave it a try. It works fine, I don't see the error with 27 extra values like you do. Probably there is something going wrong in your Fleury code and it is overwriting memory where your loop variable resides. Suggest you check the configuration settings in Fleury source files and rebuild to be sure you have a good object. The i2cmaster.S file must be edited for correct port/pin values of SCL/SDA and the makefile must be edited for the correct MCU. If that is not the problem I would try a different chip. |
September 18, 2013 by dvdsnyd |
All, Thank you very much for your help! I didn't have a whole lot of time to mess around with this tonight, but here is what I did try:
As you can see, this does not mesh up at all without changing that line...??? Doesn't make a lick of sense to me? BM, I am having a hard time understanding what you are trying to explain. What do I need to do differently? Noter, I have never really done anything with i2cmaster.S or the makefile... I am using Fleury's i2c library, but am using twimaster.c and i2cmaster.h I changed twimaster.c for the correct crystal and bus speed, but that is it? Are you using a 24LC512 too? I really appreciate all of your suggestions! Thanks again! Look forward to hearing your responses! Dave |
September 18, 2013 by Noter |
I guess it depends on where you get your copy of Fleury's code. I don't remember where I got it but it was configured for a different mcu and didn't work with the atmega168/328 until I edited i2cmaster.S to use PC4 and PC5 (lines 43-46) and then had to change the mcu to atmega328p (line 32) in his makefile and recompile. To see if the problem is in the i2c code or not just comment out lines 106 and 118 where you call the write/read code from your main. If the problem persists then try a new atmega chip. I have a couple of 24LC256 eeproms on the breadboard but they work the same as the 24LC512. Same address and everything. I didn't have to change your code at all for them to work. |
September 18, 2013 by Noter |
By the way, here is the gcc command I use to compile/link your program ... wierd problems might be caused by optimization too so try -0s if you're not using that or turn it off with -O0.
|
September 18, 2013 by Noter |
BM, Good explanation but there is no padding or alignment of structures in 8-bit environment ram. No need for concern on the ATmega's. The biggest advantage of using structures for multi-field records is simply fewer lines of code to get the job done. Also adds some readability to the code. Eases the task of changing fields, adding/removing, too. Arrays don't really come into play in realizing these advantages, they are basically the same for structures as other types of variables. I don't use single field structures unless I will/might be adding more fields later. Another reason someone may have is just to get some practice using structures. |
September 19, 2013 by Rick_S |
Noter, Fleury's I2C routines can be compiled either from the twimaster.c OR the i2cmaster.s files. You don't need both. The i2cmaster.s can be used for all AVR's as it is a software implementation of I2C. twimaster.c is a hardware based implementation used strictly on AVR's with a built in twi interface. twimaster.c does not need editing other than the mcu clock settings as I recall and possibly the I2C clock speed if the device/circuit can't handle the 400KHz default clock. Rick |
September 19, 2013 by dvdsnyd |
All, I will try to take a look at this in depth more tonight hopefully. I am thankful for this forum and all of you! I really appreciate each and every one of your helpful posts. The reason I only have one item in my structure is for testing purposes. I am planning on adding more later. Really, this was supposed to be a simple test to make sure I could write and read the sensor data to the chip, without actually implementing the sensor yet. Noter, you said- To see if the problem is in the i2c code or not just comment out lines 106 and 118 where you call the write/read code from your main. If the problem persists then try a new atmega chip.
It is encouraging that my code works for you Noter. Thank you for checking! Is there anything that is specific to the 256K version that I am mission? Do they both have 128 byte page buffer size? Rick, Thank you for explaining the Fleury routines. I use twimaster.c to compile my program. I have changed the mcu clock, but maybe I should take a look at the i2c clock speed. I think it is currently at 300KHz, Something to try anyways. If you think of anything else, let me know, I will certinally give it a try! Thanks again for all your help! Dave |
September 19, 2013 by Noter |
Thanks Rick. Just to be sure I recompiled and linked Dave's program with twimaster.o and it still works fine. Dave, read_byte_array and write_byte_array point to the same buffer so if you comment out the i2c calls whatever the write routine left in the buffer is still there for the read routine. It will look like it worked as expected but all you want to verify is that the problem still exists or not when those two lines are commented out. |
September 19, 2013 by dvdsnyd |
I just commented out the two lines you suggested Noter and the program runs as expected.. So, I am having a problem somewhere in my i2c interface? I'll take another closer look at my i2c files from Fleury and see if I see anything. I believe I am using the same ones I have been for the BMP085 pressure sensor. Dave |
September 19, 2013 by dvdsnyd |
I am at a loss right now... I tried changing the i2c SCL clock speed, didn't do anything. I tried with the -Os flag and with the -O0 flag too. To be complete, here is the makefile I am using, along with my twimaster.c file that is located in the same directory as my main program EEPROM_Test.c
|
September 19, 2013 by dvdsnyd |
One more thing, I have 2.2K pull-up resistors on my SCL and SDA lines. |
September 19, 2013 by Noter |
I don't think the i2c hardware is responsible for the error. It pretty much works or not, nothing in between. I don't have any other ideas at the moment. It does seem strange that the extra 27 lines went away when you included the i variable in the printout. So now you get the correct number of outputs but the values are not as expected? Do you want to try my hex file onto your mcu and see if it works? testavr.hex only difference is I compile for atmega328p but the 328 and 168 are virtually the same except for capacity, it should load and run on your 168 just like it does on my 328. |
September 19, 2013 by Noter |
I also upgraded to Atmel-AVR-Toolchain-3.4.1 quite a while back for tiny10 issues but I don't recall ever having any problems with 168/328 programming on the older version of the toolchain. Just mentioning because that may be another difference between our compiles. |
September 20, 2013 by BobaMosfet |
dvdsnyd- As you progress, what I wrote will make more sense. I was simply going off the fact that your struct had only one member. However, since you intend to use more members in the future, the struct is the way to go. Per Noter, your code seems to be working, so I wouldn't worry about how variables sit in RAM right now. I2C/TWI isn't difficult- but that doesn't mean it's easy the first time around. The ATMEGA168 Datasheet has an amazingly good description of the I2C/TWI process, the commands and so forth-- instead of simply relying on Fleury's library, I recommend you go study that section and understand how the handshake works. At a conceptual level. It will help you understand what's going on. One of the reasons I stress this, is because Fleury's code may not be complete, or may not work in all situations-- and unless you understand the protocol, you won't figure out what needs changed. For example, I2C/TWI isn't all that fast (not really). It's possible your read routine might actually have to restart up to 60 (or more) times before the device responds. But the only way you know this is if you check the error codes returned inside the read routine-- I don't know how well Fleury's code handles error checking. As for using 2.2K pull-ups on your SCL and SDA lines, the pullups have to be sized according to communication frequency. I know for me, at 400kHz, I had to use 1600-Ohm resistors. The ATMEGA168 Datasheet has the formula for calculating them. BM |
September 20, 2013 by dvdsnyd |
Hi Guys! Thanks for responding with ideas. Noter, I will try your hex file, but how do I go about putting the hex on the mcu? I have mostly been relying on the Nerdkit Makefile and going that route. Is there a command that I can do that will install it? It is weird that when adding i to the print statement that I get the correct number of reads, but the data is bad. What could cause that? BM, I will definitely have to take a closer look at the ATmega datasheet and get into i2c a little more. I just don't understand how my code, untouched could work on someone else's mcu, and not my own. Again, any suggestions are welcome! Thank you so much for hanging with me! Dave |
September 20, 2013 by Noter |
Use avrdude to load the hex file onto your mcu. When you run the makefile the last command is avrdude, that's the one you need but with the name of my hex file. You can run avrdude manually in the dos window like make. Looking at your makefile I think this would do it -
It is weird how it changed when you printed the i variable. I suspect there is something going wrong in the compile or link that is causing undefined behaviour. But it could be something is corrupted during program load too but that is not likely because avrdude verifies the data by reading it back and comparing to the original hex. Check to be sure avrdude is not giving you an error at the end of the load. This is what I see after a successful load by avrdude, anything else indicates an error:
Least likely but possible is something weird in your hardware which can be verified by loading my hex and seeing if it works. If it does then I think it would be safe to rule out a problem in the hardware. |
September 20, 2013 by dvdsnyd |
Thanks Noter, I will give this a try now. Do I need to have any of the twimaster.c or other accompanying files to load the hex? Or is the hex the stand alone, complete program? |
September 20, 2013 by Noter |
The hex is the stand alone complete program so nothing else is needed, just the hex and avrdude. |
September 20, 2013 by dvdsnyd |
So I just tried to download your hex to my mcu: It worked, or so I thought, but when I went to check my serial monitor (PuTTY)...Nothing came up. I then took a look at my wiring, and noticed my WP pin on the EEPROM was tied to +5V, and I think it should be tied to GND when to being used...so I tried to upload my original code using the newly wired EEPROM, and my computer blue screened for whatever reason...I'll give it one last go tonight, then I am off to bed |
September 20, 2013 by dvdsnyd |
This is what I get when I try to "peek" at the running program using the serial monitor and your hex file...Doesn't make any sense...
Now here is what I get when I download your hex to my mcu..seems to me it should be fine???
|
September 20, 2013 by dvdsnyd |
Just tried my program now with the WP pin held to GND...same result. I get the same 27 lines of junk before the good data...In each read sequence, it seems to be the same 27 lines. Any idea why my serial program wouldn't be able to work with your hex? Again, thanks so much for digging into this with me! Dave |
September 20, 2013 by Noter |
I put my atmega168 on the breadboard and loaded the hex file, same result, no serial output. Rather than try to figure it out I just recompiled for the 168 and it works again. Sorry about that. Here's the new hex file that works on the atmega168 Test_AVR.hex. |
September 20, 2013 by Noter |
I compared the 168 and 328 hex files and the only difference was the initial value of the stack pointer. AVR-GCC places the stack pointer at the top of ram memory and the stack grows down from there. Since the 328 has twice the memory, the stack pointer for the 328 hex points to non-existent memory when loaded on the 168 and the program can't run. Back in the day when I was migrating from the 168 to the 328 I would load my 168 programs onto the 328 chip and they would run fine. Although obvious now, the stack pointer was set to the middle of ram on the 328 and everything still worked. Now that I think about it, this is the 1st time I ever tried to go the other direction, 328 to 168, and it won't work because of that stack pointer. |
September 21, 2013 by dvdsnyd |
You should be sorry! Your silly Test_AVR.hex file was what did it in for me! (100% kidding) Again, thank you for your efforts! I tried out the 168 hex you provided, and IT WORKS! Hrm...Wonder what could be the problem still though?? Do you want to post your twimaster.c file, as well as the compiled twimaster.o...I could try linking the twimaster.o...and see if it works. As well, try compiling and linking the twimaster.c file to see if that works... Let me know what you think? Thanks again! Dave |
September 21, 2013 by Noter |
LOL! Here's all the files from my test directory Test_AVR.zip. If none of these help to solve the problem then I think you should upgrade to the latest avr toolchain ... Atmel AVR Toolchain 3.4.2 for Windows and see if that takes care of it. About the only reason we could get different results when compiling the same programs is we have different versions of the compiler. I've been at 3.4.1 but am going to 3.4.2 now that I see it's available. I like staying on the latest and greatest version of the tools. |
September 22, 2013 by dvdsnyd |
:-) Thanks Noter. I downloaded the Atmel AVR Toolchain 3.4.2 for Windows. I installed it as well. Do I need to do anything else? What about the header files? IO haven't had a chance do much more than that today...been a busy weekend. Hopefully tomorrow! I'll definitely keep you posted on the results! Thanks, Dave |
September 22, 2013 by dvdsnyd |
If it wasn't obvious already, I just wanted to say, I am running a version of WinAVR from when I first started with the NK 2.5 years ago. It is probably not the most recent version. Is there anything that I need to do differently with the AVR Toolchain? Or when I installed the avr toolchain, did that become the default? Thanks, Dave |
September 22, 2013 by Noter |
I think windows installer takes care of everything related to the new version of the toolkit. You can verify the version with
at the command prompt. Might have to open a new dos window or worst-case a reboot to get the new variable assignments. There is no installer for it on linux, I just unpack the download into a new directory, modify my path variable to include that directory, and open a new command window - easy as pie. |
September 22, 2013 by Noter |
This is the last line printed when I verify with "avr-gcc -v":
|
September 23, 2013 by dvdsnyd |
Thank you Noter for the files once again and the explanation of how to verify the version. Installation was flawless... So...It seems to be working now. I am wondering if the problem was that I wasn't cleaning out my old .hex and .o files. Because, I cleared out my old .o and .hex files before dropping Noter's twimaster.c file in place of mine. And it worked. Then I cleared everything out again, even the.hex file, and replaced everything with my own stuff, and again it worked. Could this have been the issue? Seems like a stretch to me, but it is all I can think of at the moment...without giving it a whole lot more testing... Thoughts? Dave |
September 23, 2013 by Noter |
Glad it's working - always fun to figure things out ;-) I don't think old .o/.hex files were an issue because in your makefile twimaster.c is recompiled everytime EEPROM_Test.c is compiled. And EEPROM_Test.c was compiling becauase you would see changes when you worked on it. I think this one was caused by something broken in the old version of the toolkit and something specific in the way you were doing things found it. You could go back to the old version to verify but you're better off with the new toolkit anyway so it would just be academic. Now that you have v3.4.2 you'll probably be good to go for many years but still it's a good idea to check the ATMEL site every year or two and upgrade when there is a newer version. Did you notice the comments in twimaster.c, Fluery compiled with AVR-GCC 3.4.3 which is even newer but I like to go with whatever version ATMEL has published on their site. BTW, there's a newer version of avrdude too. Something to keep in mind if you ever run into problems installing your program onto a new type of atmega mcu or using a new programmer. You can check your version with command 'avrdude -v', I use v5.11.1. |
September 24, 2013 by dvdsnyd |
Thanks again Noter, I will have to go grab the new version of avrdude like you suggested. One thing I forgot to mention in my previous post is. After I got the new version of avr toolkit installed, I tried to make my program. I still got the 27 extra leading reads. Then after I deleted my .hex and .o and put your stuff in, it worked. Then I did the same and just replaced it with my old stuff, and it worked. Seems strange to me. I will have to spend a little more time with it and make sure it is truly working the way I intend. I'll keeep you posted! Thanks, Dave |
September 24, 2013 by Ralphxyz |
Dave what does the final version of your code look like? Ralph |
September 24, 2013 by dvdsnyd |
Ralph, It hasn't changed much from the stuff already posted in this thread. It isn't totally final either. The code that I posted a few days ago is the code that I got running last night. Use "CTRL + f" or pull up your browsers "find" and type 6 days, 14 - This is my EEPROM_Test.c file. To find my makefile and twimaster.c files type 4 days 12 - Should be 2 matches here, one is the code. (Sorry kinda hokey, but hopefully it will help, I am at work now) I can try to post the whole thing later if you would like. Are you trying to do something similar with EEPROM's Thanks, Dave |
September 24, 2013 by Ralphxyz |
I went through this 2 years ago and thanks to Paul's help (Noter) I sorta got it to work, now I have something new so I like to have working references. Ralph |
September 24, 2013 by Noter |
With your make file you only get a fresh compile when EEPROM_Test.c has a newer time stamp than the EEPROM_Test.o. So just installing the new toolkit and running make without editing EEPROM_Test.c would skip the compile and only run avrdude to install the existing .hex onto the chip. Did you edit/save EEPROM_Test.c after installing the new toolkit so it would compile? |
September 24, 2013 by dvdsnyd |
Ralph, Hopefully, once these little bugs are worked out, I am going to turn my code into a library. At that point I'll share everything again. Noter, I deleted the existing .hex and .o, so as I understand, it would have had to re-compile. To answer your question, No, I did not edit or save EEPROM_Test.c after installing the new toolkit. |
Please log in to post a reply.
Did you know that binary numbers use base 2 to represent numbers, and these are important for understanding microcontroller registers? Learn more...
|