Ok now for the fun part, CODING!! Below you can see every line of code for my main.c file. If you are using an STM32L0 and Keil without HAL or SPL this should compile just fine, otherwise sue me.
lines 1-3 are self explanatory.
lines 1-3 are self explanatory.
6-9 are function prototypes for some functions I used, I would include them just for now because I did the timing calculation based on 32MHz and I also threw in a delay in between read and write operations because the EEPROM needs some time to do that actual writing.
22-25 I make some variables to store data, and the data which i will be transmitting as well as a counter variable to keep track of bytes sent. Note that on line 23 I add 1 to the length of string and hence the num_bytes, this is because on top of sending this string over I also have to send one byte consisting of the address where ai want to start storing the string , so the total number of bytes I have to send is all the string characters pluss the intial adress byte, this is why I added 1.
28-30 just like any other thing we have to enable the clocks for the i2c1 peripheral and the clock for the pins it will use.
32-36 if you remember from the Part one of this post, we must set the pins to Alternate Function with open drain
38-40 can be used to enable the internal pull ups, since i2c requires pull up on the clock and data lines, I dont need to do that because the EEPROM chip has external pull ups on the circuit board.
43 We go into the Alternate Function register for GPIOA , this register is an array of 2, so it has AFR and AFR It allows you to choose what alternate functions the pins will have. AFR corresponds to the lower pins 0 - 7 and AFR pins 8 - 15. So i set AFR 1 and 2 which correspond to pins 9 and 10. I set those to 1 which means alternate function 1 which from in last post I told you it was i2c mode.
46 I set the timing register, like I mentioned this is not so straight forward and if you find a good way to calculate it please enlighten me.
48-54 Here I make the necessary settings to the I2C1 registers that correspond to the current transmission I want to send which is as follow: I want to send a write operation to slave at address 0xA0, this transmission will have a certain number of bytes (num_bytes), I will be using 7 bit addressing mode because my chip does not support 10 bit addressing. I do not want to enable the auto end feature, so instead of sending a STOP condition when the number of bytes is sent, the peripheral will let me know its done by setting the TC flag. That way I can handle what to do next. Ultimately I enable the peripheral.
64-66 I send the START condition to begin communication, I wait for the TXE to be ready ,then I write the first byte in the TXDR register, this first byte I am writing is the memory address where I want the EEPROM to begin storing the data. After every byte I send it will increment its "internal pointer" to the next available address, so I only have to give it the first initial address and it does the rest. (do not confuse this memory address within the EEPROM with the actual EEPROM slave address)
70 This while loop will go through all the bytes we have to send, note the minus 1 because we have to exclude the first byte for the address because we already sent that in the last step.
79-83 Since we disabled the auto end feature the I2C will generate the TC flag telling us the number of bytes we specified to send is complete (in the next operation we will take advantage of this feature) So we wait for this flag to be set, then we send a STOP condition and I added a delay because the chip needs time to write this data and the microcontroller is so fast it will seem almost instant once we start reading with no delay in between.
87 Dont forget to reset count
89-99 Is identicle to the write operation, this is because to read from the EEPROM you must first send a write command with the address you want to start reading from, once you do that you have to send it another START condition and then begin reading. The first write command is so that it can move its "internal pointer" to the write location. Afterwards you can just keep reading data from it, preferably in 8 byte chunks according to the datasheet.
103-108 I reconfigure the i2c this time I enable auto end,cwhich will send a STOP condition once the number of bytes programmed in the NBYTES register is complete.
110 This will cycles the number of times needed to read the bytes from the RXDR register when ever new data is ready
I hope I explained everything well enough, if not shoot me a message. Follow me on Instagram for a quicker reply, dont just message me a random question, tell me it is about something posted here on my blog. https://www.instagram.com/edwinfairchild/
In the next part we will take the structure of this code and make C and H files to make a simple I2C driver along with necessary functions like I2C_send and I2C_read and anything else we might need.