Project Journal for Cole Roberts

CUMMULATIVE: 132.25 hours

=============== Week 14 (16.5 hours): =================

=========== Entry 6: =============



Date: 2025-04-18
Start Time: 19:30
Duration: 3 hours

Right now I am working on the rewrite. Before we had massive if else chains within each case of a switch statement to determine what each button does in each state. This was messy and in that implementation only one button press would be registered even if multiple were pressed in a short period of time.


To fix the overall structure I am having six different button events, one for each button and then short and long press. We will then have an array of function pointers that is indexed based on the state and the event. Each of these will correspond to what each button press does in each individual state.



example1

I will also being setting up a FIFO queue so that all buttons pressed will register and will execute a refresh each. So now all the button interrupts do is push their respective button event to the FIFO queue and the state machine takes care of the rest.


I just wrote all the code to test this and only ported over the home menu for testing purposes. Time to test!


So it seems to be working fairly well! Except it seems I cannot use WFI for halting the while loop. I am not sure if we are having extra interrupts that I don't know about, but it keeps passing that instruction even when there is no button presses.


To avoid this I just added a flag for the number of interrupts that have been triggered. When an button interrupt is called it increments this flag and once we handle it, aka pop the event off the queue, we decrement this flag. When testing earlier I only had it as a bool and this was still breaking when doing multiple button presses, since the state machine would only run one cycle instead of the multiple required, unless the interrupts were spaced far apart enough to catch the flag when it was low and set it high.
example1


=========== Entry 5: =============



Date: 2025-04-18
Start Time: 13:30
Duration: 3 hours

Checking BUSY pin. High for ~1.2 seconds

I don't understand, BUSY is high for that long. But from the start of my render function until after the wait for IDLE is only ~200ms. It is only in the wait function for the time of my hardcoded delay. That means that the file loop waiting for BUSY is not even doing anything??


So BUSY is ONLY high when the display is executing a render. If you are writing to the display it does NOT say it is busy.


So I changed it such that I set a flag saying the eink is busy once we start rendering. Then the flag is set low upon a falling edge interrupt of the BUSY pin going low.


So finally the display is only halting the system while its actually busy and not a hardcoded amount of time. But we are still having issues. If I execute multiple renders back to back it can update pretty quickly. But if I try to go at that same speed with the buttons it still is not working. I need to do the refactor I am planning and see if that can help.


So the code for handling state transitions and button presses is hacked together and messy. I think I can make it significantly cleaner and maybe faster too. I am planning on having many different events. These will be specific button presses based on the state you are in. Every single event will have its own handler stored in an array. This will make it very easy to add new states and control what each individual button press does within each of those states with only a few lines of code. I also want to be able to coalesce button presses. I am going to queue events (button presses) when they happen even if the display is rendering. If there are multiple of the same in the queue (such as two down presses) before a render is executed, we can then execute the logic and write both of them to the framebuffer before rendering. This removes the need to wait until the screen is fully refreshed before pressing the button again, and will remove multiple renders happening for multiple of the same button presses. This is particularly helpful when navigating the menu.


We tested the battery monitor PCB IC on the secondary I2C lines because Hannah flywired it. It still reads 0. But if we hookup the module to those same lines and use the same firmware we get the battery percentage. Therefore we finally can confirm is is the battery monitoring hardware on the PCB and nothing to do with the MCU, I2C lines etc.


=========== Entry 4: =============



Date: 2025-04-17
Start Time: 16:30
Duration: 2 hours

We still have no idea what could be the problem with the battery monitor. We think it could have to do with the I2C peripheral since we using a different peripheral for the module. We had the issue with the SD card SPI where the pins themselves weren't working until we did something special with them.


The SCL and SDA lines seem to be always high? That would mean nothing is pulling them down. We are using 10k pull-ups, the module has 4.7k. So maybe the higher resistance is making it harder to be pulled down and the MCU is unable to pull them down to send a command to the monitor?


So after changing them to 4.7k we still don't see any changes.


We pulled out the AD2 and it seems that the MCU is sending stuff when on the alternative I2C peripheral? I think we need to test with that one and finally confirm what is up.


Similar to the SD card SPI we just initialized the I2C lines as outputs and tried toggling them normally to make sure that they work. They seem to be working. So I am not really sure why they wouldn't work for I2C???


=========== Entry 3: =============



Date: 2025-04-17
Start Time: 10:15
Duration: 4 hours

So before my font renderer would only work when the width of the font was 8. I had modified it to work with variable heights but the widths was not working. I finally figured out why and updated the renderer. So if the width is greater than 8 that means there is more than 1 byte for the width. So we have to have a third inner for loop that iterates over the number of bytes in the width and will draw the first one and then move the x pointer over by 8 and draw the second one.


Also added setting for choosing small or large font.


Since the buttons are on the side of the device, it default to the buttons being controlled with the users left hand. I figured that some people may not like this. Therefore I added some functionality to be able to rotate the entire display 180 degrees. Therefore everything will be flipped and you can turn the device over and the users right hand can control the buttons instead.


Allowing them to choose their dominant hand is actually fairly easy. The eink display we use has configuration options which allow the ability to configure which way we write into the internal RAM and where we start. So I have it set to start at the end of RAM and flip which way the x and y pointers increment/decrement.


We found it annoying to have to remember, and sometimes forget, which button does what. For that reason I have added little icons on the screen next to the buttons which show what the button does, such as a little up or down arrow. These button hints change depending on the menu, so in the flashcard menu it will show arrows that point to the left and right instead.


We were having some issues with the packaging and struggling to fit everything inside. The packaging people printed a spacer to extent the thickness of the packaging. I met with someone from the packaging team to help them install that. It makes things much easier now.


The way we have the buttons is pretty poor. We don't have headers for some reason so we had to manually solder headers onto the individual pads. This leads to them being very fragile. I accidentally broke one of these off. Luckily the pad did not get pulled up. I spent some time soldering it back on, takes a while when solo.


=========== Entry 2: =============



Date: 2025-04-16
Start Time: 14:30
Duration: 3 hours

We are still having issues with our reset button. We desoldered the one that was on there and decided to try another one. Zoe went in to lab today and was saying that it said the STLink was unable to reset the micro. After looking at a picture of how the button is connected it looks incorrect. It seems to be connected in a way that is always pulling it low so we will fix that.


But we also thought not having populated our pull up resistor was causing issues. After looking at the datasheet it seems that NRST has an internal pull-up resistor. I had no idea about this. They claim its "weak" but its 40kOhms. I am not sure why we have the issues in regards to not being able to reset without having the STLink plugged in sometimes... I thought this would resolve it but since there is an internal pull-up, probably not.


Power switch stuff


I can turn off, but no interrupts are triggering in STOP 2 mode.


For now lets just not do lower power mode for MCU...


=========== Entry 1: =============



Date: 2025-04-13
Start Time: 13:30
Duration: 1.5 hours

Right now I am working on getting it so we can display if the battery is charging or not. It seems that the battery charger exposes a pin called LBO that goes LOW when the battery is being charged.


I have just set up this pin to be an input and made a function to read it in. I am displaying the string "CHRG" near the battery percentage if the battery is currently charging.


I also merged all of these UI, RTC and SD card changes. Once Zoe finishes parsing the number of cards I can display that on the UI. Also once we solder buttons back on I can test saving and displaying the last studied date as well.


Not working wihtout stlink, R1 issue?


=============== Week 13 (13 hours): =================

=========== Entry 6: =============



Date: 2025-04-10
Start Time: 12:30
Duration: 2 hours

RTC working! Had to set some extra enable bits and turn LSI on. The RTC APB enable bit is not the only one, there is another RTCEN bit as well. On top of this you have to do a backup domain reset first which I did not realize at the time.



example1

Why don't I need to do BCD->Dec when reading? One thing I am really confused on is the format of what is stored in the RTC registers. I have to convert my decimal input to BCD to put them into the RTC registers. But when I read the data back I do not need to convert back to decimal? When I was just trying to do that I was getting invalid data. I tried removing the conversion and it somehow was working?


Date seems to be 0 even though I am setting it. Upon further testing it is only zero on the first read, this is odd, because even if I give it a delay its still on the first read. For now I am just putting a dummy read right after initialization. Not the best fix but we don't have a ton of time to get to the bottom of it right now.


So the SD card is not mounting for some reason. We have soldered it on and it looks like its getting the proper voltage. For some reason it looks like the SPI pins are not even doing anything?


To test I am trying to just enable CS as an output and toggle it in main and read it from the scope, its literally not toggling. But if I do the same logic to toggle the LED it works just fine? I have no idea why we cannot even toggle a GPIO pin


So for some reason GPIOG 3-15 are electrically isolated by default. You have to set a bit in the PWR peripheral to get rid of this isolation. All of our SPI pins were in this range, that is why they were not working. Thankfully Zoe searched it up andfound this forum post which told us about this isolation.



example1

=========== Entry 5: =============



Date: 2025-04-09
Start Time: 14:30
Duration: 2.5 hours

Looking into LFN since Zoe mentioned it as an option for num card stuff, also gets around only having 8 char deck names. Upon looking into FAT more it seems that the reason for the 8 char deck names was because fat only allows 8 char for the actual name and then reserves 4 more chars for the file extension, Zoe figured this out.


I am now looking into RTC since we want to show the last time the user studied a specific deck and hopefully track how long they have studied overall. As of now I am going through the initialization sequence given in the datasheet, this may take a while.
example1


So I have written the entirely of this initialization sequence and wrote some code which I think will read it back when we want to see the value in the time and date register. Upon testing nothing is really happening though. So it looks like it is getting stuck on waiting for the INITF flag, this means initialization is not finishing? I must be missing something but man lab is over so I will look into it tomorrow.


=========== Entry 4: =============



Date: 2025-04-08
Start Time: 13:30
Duration: 3 hours

Mark got the buttons soldered onto the PCB. So now I have to start testing them with the firmware. We firstly checked to make sure the buttons are working, we measured voltage across them. It is ~2.9v, this is within the range of it being a 1 so that is okay.


The interrupts don't seem to be triggering though? Not really sure what is going on. The waveform of the button is excellent so the debouncing circuit is working properly. We also just measured the voltage on the actual microcontroller pin and it is being propagated there as well.


Okay so it turns out I just forgot to call the function to initialize the buttons. I had this commented out before the buttons were actually installed, whoops.


So now that they are triggering both 4 and 5 are constantly triggering, this is taking up basically all CPU time and even the screen won't render. I am clearing the pending bit so it can't be software. We know the waveforms are good so what is going on? Okay it turns out that I was indexing the SYSCFG registers wrong.. I accidentally increased the index so it must have been some sort of undefined behavior.



example1

I was trying to draw the image The team wants to add UI stuff so I am looking into drawing an image on the display. At the minimum I wanted to draw the sleeping emoji when the device is sleeping. It is actually not that difficult, we just have to go through bit by bit of the image and write it in the framebuffer, I was forgetting to divide the index by 8, that is why this took me longer than it should have.



example1

example1

=========== Entry 3: =============



Date: 2025-04-07
Start Time: 13:00
Duration: 1.25 hours

I want to center the menu on the display. I need to figure out the best way to go about calculating the offsets. Right now I am attempting to get the total height of the menu based on how large each item is and how much spacing is inbetween each item. I can then subtract this from the total height and, I think, divide by two to get the starting y height.


=========== Entry 2: =============



Date: 2025-04-07
Start Time: 10:30
Duration: 1.25 hours

Got stuff hooked back up, still works. messing around with UI, merged PRs


So we are getting ready to get the preliminary checkoffs. Zoe and I hooked up the battery and 5v from the power supply and both seem to be working and give 3.3v output.


We tested flashing the microcontroller and writing to the display and all seems to still be working on that front as well. Waiting for TAs to come and we will get check us off.


I would like to make some UI changes. Right now we have to go through all kinds of complicated button mappings to be able to go to different menus. I think the solution is just to have another menu at the start where one can select studying, download, settings etc.


I just merged the newpins PR and my button refactor PR, I had to resolve some merge conflicts but they were fairly simple.


I implemented the new menu, its rendering properly but I am not able to test to make sure I can properly navigate to different states based on selection because we do not have buttons hooked up on the PCB yet.


=========== Entry 1: =============



Date: 2025-04-05
Start Time: 13:00
Duration: 3 hours

Hannah soldered the MCU yesterday since we confirmed that we are getting a consistent 3.3v from our power system. Before powering it on we of course needed to make sure there were no shorts. So we have started continuity testing and our first short seems to be on 3.3v and GND?? It doesn't look shorted though.


So all of that 3.3v and GND are shorted together, we just realized that means that if only one is shorted that all would be shorted together internally so thats why the continuity test was beeping for all of them.


List of shorts: 30-33 shorted (GND and 3.3v) 38-39 shorted (GND and 3.3v) ** possible short, check after 106-107 71-72 shorted (GND and 3.3v) 83-84 shorted (GND and 3.3v) 106-107 shorted (GND and 3.3v) **** CLEAR SHORT, fix this and retest 120-121 shorted (GND and 3.3v)


We removed the clear short on 106-107 and now its all resolved! Hannah did a great job, soldering all of those pins and only having one small short.


Mark soldered on the programming header and now we are able to attempt to flash the MCU. I wrote a basic blinky program to blink one of the LEDs on the board as an initial test.


So when I try to flash the code it says successful but nothing is actually happening with the LED? When I try to erase the flash it also says that the NRST pin cannot be pulled low by the ST-link.


They said they didn't solder on the NRST circuity yet, doing that now.


So we put the button on and it seems its reversed, the default state is pulling down...


We put a different button on with fly wiring and were able to get that fixed. Now we can flash the MCU with the LED blinky code and it works!!!


We just soldered on the e-ink header and we can write to the e-ink too. This works with 5v being supplied AND off of the battery power!


We probed the PG and STAT pins on the charger and they are all giving us the correct statues, telling us when the battery is being charged, when USB vs battery is powering etc


=============== Week 12 (9 hours): =================

=========== Entry 4: =============



Date: 2025-04-03
Start Time: 15:00
Duration: 1.5 hours

Today I am just working on the safety doc. I did the calculations for λp and MTTF for our major components. They seem well within range!


I also started on the failure points and uploading the pictures of each subsystem from the schematic.
example1


=========== Entry 3: =============



Date: 2025-04-03
Start Time: 15:00
Duration: 1.5 hours

I am looking into some more power stuff, I wrote functions to shut down what we are able to and then enter the low power mode for the MCU. I just need to test this and also set it up to actually be triggered by the power switch. Right now we don't have that set up on our prototyping board so I have not written the IRQ handler yet.


But it is fairly simple, on a falling edge I just call my power off function and on the rising edge we call the power on function which just resets the MCU.


I am not sure on some optimization stuff. Because I am not fully sure what exactly will lead to the best power conditions, I think we should probably turn off all clocks and set pins to analog etc.


I also reviewed the PR that Zoe made for moving over the whole codebases pinouts to be for the PCB, as most of the pinouts are different from our devboard, also have a slightly different MCU. She made some more changes after I left yesterday.


=========== Entry 2: =============



Date: 2025-04-02
Start Time: 15:20
Duration: 2 hours

I am working with Zoe on integrating the battery monitoring that Hannah wrote. They currently have it set up to read the state of charge. I am not sure what that is but it is saying 72% while we are also reading ~850, but the battery is 2000mAh. This does not make sense.


We are pulling all of the data possible to investigate. There are tons of registers we can read from including voltage, state of charge, capacity, full availability, remaining capacity and more.
example1


So it turns out that the battery is just bad, the full charge capacity was only ~1200mAh, so that makes more sense and it does seem that the state of charge is indeed the current battery percentage. That is all that we will need in our firmware.


We aren't fully sure when the MCU will be on the PCB and be ready to test, but we are starting to prep for when that comes. For prototyping we are using the STM32L432 and in our final design we are using the STM32L496. Therefore we have to go through the entire codebase and update every single pinout to match what is final on the PCB.


This took a bit longer than expected, Zoe and I just did most of it together (pair programming). We had to edit the majority of the files.


=========== Entry 1: =============



Date: 2025-03-31
Start Time: 10:00
Duration: 3.5 hours

Since our hardware testing is a delayed I have decided to start adding new features to the device. Today one feature I want to polish is deleting decks. I recently did the whole refactor to make it easy to add features like this, so we added where if you hold down the select button on a deck then it would delete it. But a user could accidentally delete a deck this way. So I want to add a confirmation menu so they can be sure they want to delete it.


This was fairly simple, I just needed to use the new button framework and create a new state since there is a new menu.


While I still have time I also want to add an option for users to choose settings. The only two options I can think of right now are shuffling decks and a learning algorithm.


So to go to this settings menu I am trying to be able to hold down the forward button to get there. For some reason once I hook up the debouncing circuit to that button everything freezes up? I don't really know what is going on there.


Other than this though it works. I can toggle if I want to shuffle the decks or not. I have not actually implemented the learning algorithm but if/when I do, there is the ability to turn it on and off now.


So now the settings are saved into RAM which I believe persists in Stop 2 mode as well (I will check on this). I do need to write them to disk though in case the device dies or if we were to implement fully power down in the future.


I checked and SRAM does persist in Stop 2 mode. So if we run out of time we can just not write these settings to the disk and have them persist in RAM. This is obviously not a good idea for a product that is being shipped, but it would be corrected later.


Could the forward button not working for debouncing have something to do with the fact that it is one of the ones that works for multiple interrupt lines (EXTI 5-9)?


Okay so I just tested it by hooking it up to another buttons debouncing circuit that I know works and we had the same issue with the constant triggering.


Okay so I checked and somehow once you press the button hooked up to PB6, the ouotput stays high for some time. I tested this with the debouncing circuit too and it stays high for a very long time, probably because it charges the capacitor up a lot from staying on longer?


So the issue only occurs once I initialize the eink display. Also PB6 gets a pulse every time the eink writes? Is it somehow hooked up to eink busy pin? Maybe something with that is why we needed a delay in the wait busy function? Something weird is going on here... I need to try probing eink busy along with it and see if its somehow the same.


I just tested it and when the eink busy pin goes low (not busy), PB6 goes high. How is this possible. I don't know if it has anything to do with it but the eink busy signal is very noisy.
example1


Wait I think I may be dumb, pressing the button itself doesn't mean anything as it makes a screen update which would make the display busy. But it does happen upon reset which is the weird part.


Also pressing any button seems to be bringing PB6 high. This means that after all maybe busy and PB6 connected somehow??


=============== Week 11 (8 hours): =================

=========== Entry 5: =============



Date: 2025-03-27
Start Time: 14:30
Duration: 2 hours

Today my goal is to setup holding down the select button to delete a deck off of the device.


To get this to work I need to refactor. Currently the button handling is a mess. Right now in each handler we handle changing states. Within the state machine case statement we don't actually do any state transitioning. In the beginning this was fine, it worked but wasn't the most ideal. When we try to add new features we have to hack it into that current setup.


The ideal setup (which I am currently implementing) is to have the button press and its type registered somewhere. For example all the button ISR would do is I hit the Select button and that it was a long press. Then in each state of the state machine I can handle each button and press type combination. This makes things significantly more modular. We will be able to add anything we want and have it be triggered by button presses and not have to hack it into the button ISRs.


So I have moved everything out of the button handlers now. All they do is specify which button was pressed and if it was short or long. This opens up a whole world of possibilities now, we can do basically anything with the buttons.



example1

example1

These changes made adding deleting decks trivial. I just had to add a call to delete_file() in the long press section of the main menu state in the state machine.


Right now I have basically have a mutex in the button ISRs because we did not have debouncing before. I presume that this will be able to be removed once all of the buttons are debounced. I need to verify this though, as I tried removing it from one debounced button and it seemed to cause undefined behavior.


=========== Entry 4: =============



Date: 2025-03-26
Start Time: 15:30
Duration: 2.5 hours

So we are starting to realize that we did not fully think about power consumption and shutdown properly. Originally I think had suggested we do some combination of bulk capacitors and have the power switch be managed by software. I am not too sure what I was thinking because this is not the place to use bulk caps.


We ended up going with a fully software based power off system. We figured that we would be able to put everything into a sleep mode of sorts and have power consumption be negligible. The reason for this was in case we needed to have some time to clean up the software being actually losing power. It turned out to be a poor choice and a learning experience.


It turns out that we cannot actually sleep some things such as the SD card. We should have done one of the following options:
1. Had the power switch directly be connected to hardware with bulk capacitors and be able to read it via GPIO. This would make it so that once the switch is flipped software can realize that and quickly clean up before the bulk caps run out and the system powers down.
2. Had the power switch be fully handled in software BUT have MOSFETS to turn off power to each component. We could have controlled power to each component with MOSFETS, although in retrospect this option is still worse than option 1 due to extra software and GPIO requirements. Option 1 would have been the best.


During our testing we found out that the SD card reader consumes 3.5mA during idle and ~4mA during a read. Since we don't have a way to power it off via software or hardware we are stuck with it always running. This will make the battery drain quickly on our device. If we make a PCB revision or were to actually go to market with this it would of course be resolved.


The app doesn't seem to be able to update flashcard sets, aka reupload the same one with changed components.


Turns out we were appending to the file on the SD card instead of overwriting it. The SD card flags are weird so we are just removing the file and then recreating it as there doesn't seem to be a way to overwrite unless we are looking over it. This seems odd though.


=========== Entry 3: =============



Date: 2025-03-26
Start Time: 09:30
Duration: 1.5 hours

I am currently getting a bit side tracked with feature creep. I implemented the ability to shuffle the deck so one can study the deck in a random order each time. The order is different each time they open the deck.



example1

I am also currently also working on a "home" page for each deck, where settings can be selected such as the ability to shuffle, maybe see stats, etc


I am starting to realize how poorly and non-modular this code we wrote is. A lot of stuff is hacked together to get it working instead of making it well thought out. Therefore it is hard to add new pages, menus, etc.


It would probably require a refactor to be able to display a new menu that allows the selection of randomizing or not, showing deck stats etc. If we do not do this I don't know the best way to do randomization. Should it be the default?


=========== Entry 2: =============



Date: 2025-03-25
Start Time: 15:00
Duration: 1 hours

I have begun looking deeper into the sleep states and working on the code to actually get it working.


Upon looking into it, its fairly simple. Stop 2 just needs us to set our desired low power state to Stop 2 in the power control register. Then setting the deep sleep bit in the Cortex M4 System Control Register and then calling WFI. Once we do that we will be put into Stop 2 mode.



example1

The only problem is that in Stop 2 mode ANY EXTI interrupt will trigger a wakeup. So we need to disable everything that is not the power button.


For the power switch we will need both falling and rising edge triggers. The falling edge trigger will ensure that everything else is put to sleep (display, sd-card reader, battery monitor etc), disable all other interrupts and then go into Stop 2 mode. The rising edge will wake the MCU back to Run mode. In this part of the ISR we will also call a system reset from software. This is so we can go back to a predictable state and have everything be reinitialized again.


=========== Entry 1: =============



Date: 2025-03-24
Start Time: 12:00
Duration: 1 hours

Today I am starting work on the power switch logic. This is not something we have prototyped so I am hoping everything will be okay with it.


As I am looking at this we may be in some trouble. So the lowest two power modes are shutdown and standby, we don't need to save anything as it is supposed to simulate a full power down so we probably just want to do shutdown mode, this only uses 0.23uA of current!


So upon further inspection we cannot use shutdown mode. The only way to resume execution after shutdown mode is by one of five specified wakeup pins. We did not know this before and therefore did not configure our power switch to be on one of these wakeup pins. This may mean we have to give up a lot of battery life as we cannot access the lowest power modes.



example1

Thankfully we are saved, there are some low power modes that accept any I/O pins as wakeup pins. And thankfully one of these, Stop 2, is still fairly low power at 2.86uA, so the difference is practically negligible.


=============== Week 9 (5.25 hours): =================

=========== Entry 4: =============



Date: 2025-03-13
Start Time: 16:00
Duration: 1 hours

I worked on actually implementing the state transition logic into the long press vs short press logic. Now we are able to hold the back button to go back to the main menu or go to the download state if we are already in the main menu state. I had some issues because I forgot to say that a render was pending outside of just the short press. Therefore after the long press it was actually updating the internal state but the display was not rendering what was updated internally.
example1

=========== Entry 3: =============



Date: 2025-03-12
Start Time: 14:45
Duration: 1.5 hours

I am in lab now trying to test this long press vs short press. But now for some reason the interrupts are not even triggering, or atleast the display is not updating.


Interesting, so if I try to clear the pending bit at the end of the IRQ handler that is when problems arise, but if I do it in the beginning like before its fine.


I spent some time looking at the footprint verification and noticed that all of our headers were too small. I told Mark about this and he rerouted a few things and made the header/connectors normal sized.


So right now with the non-debounced buttons if you hold down the button it keeps going into the interrupt over and over. This doesn't make sense because it should only be on the RISING edge, not always when its 1. Maybe this is because its going 0 to 1 really fast because its bouncing? But it should end up being stable after some time, unless we are doing micro-movements that are making it bounce.


So I was really struggling with debouncing the button for some reason. Zoe helped a lot and we ended up figuring it out. I think part of the reason was that the pin we were using, PA2 was used in the built in st-link... So that was causing some interference.


Now we are able to detect long versus short presses. I just need to work on setting up exactly what the long presses will do depending on where in the menu the user currently is.



example1

=========== Entry 2: =============



Date: 2025-03-12
Start Time: 13:15
Duration: 1.5 hours

So I have decided to just hijack the timer that I use for delays to also use for detecting long presses. It is setup to always be running and to have one tick be one millisecond. Therefore I can just do similar to what I do for the delays, and grab the start and check how much time elapsed by the falling edge.


I also spent some time considering the state machine. I would like to use have the state machine only run if there is an interrupt, aka run the WFI macro at the bottom of the infinite loop. But the problem is that the download state should just go straight to the main menu and doesn't need a button press, therefore there is no interrupt. I am trying to figure out the best way to resolve that.


Right now I am thinking of just telling the user to press any button to continue, that is seemingly like the best solution at this point.


=========== Entry 1: =============



Date: 2025-03-10
Start Time: 15:30
Duration: 1.75 hours

I am getting started working on fully navigating the menu. Right now we are unable to access all parts of the menu without modifying the code. This is because we only have 3 buttons and all are being used.



example1

The two options are as follows:
1. Double/triple pressing:
- This is good as it is easy for the user to understand, they just need to press a button two times to go back to the main menu, instead of the one time for its primary function.
- The downside of this is having to wait a fixed interval. So after the first press, if there is another press shortly after it can be determined as a double press. But if the user wants to do a single press then there will have to be a waiting period to wait for a second press regardless. This will be a source of input delay and that takes away from the user experience.
2. Long pressing:
- This is still pretty good for the user, they will have to hold the button down for a fixed interval. This will probably take longer than it would to just double press the button quickly, but this extra functionality is only used for going back in menus or to special menus. This is not something that the user will be doing often.
- This removes the downside from double pressing. This is because once the button is let go, we can instantly determine if it was a short or long press based on how long it was held. Therefore we do not have to have any input delay in the majority case (short/single presses).


So because of the pros and cons we are going to go with long pressing.


Originally I was thinking of implementing this similar to how Niraj does de-bouncing in 362. Constantly storing the values of the button, if it becomes 0 at any time then we can see how much time elapsed and determine what to mark it as. Niraj had mentioned this during our design review.


I have now thought of a cleaner solution. We can setup the buttons to have both a rising and falling edge trigger. On the rising edge we start a timer, and on the falling edge we check the value of the timer (aka how much time passed). This completely negates the need to poll the button and check when it is released.


=============== Week 8 (9 hours): =================

=========== Entry 6: =============



Date: 2025-03-06
Start Time: 13:00
Duration: 1.5 hours

I am trying to get variable fonts to work. I wrote it the other day but I was unable to test it. My algorithm seems to still be working for 8x8 but not for anything that has 2 bytes, so anything bigger than 8x8. I did get some fonts from the Linux kernel source code that will work though!


Right now I made a modification that takes into account the bytes per row so it can actually grab the correct character. Because anything bigger than 8x8 will have more than 1 bytes per row so it needs to go deeper into the array for each character.


Turns out I need to go through the for loop extra times if there is more than 1 byte per row. So I just multiply the height by bytes_per_row!


This is messing up my wrapping function though. Maybe I am not properly taking into account the width of the font? I think that the centering is only messing up for single line strings (no wraps).


So the reason it was all messed up was because I accidentally switched up the height and width. Once I fixed this my code started working again, I had to revert some changes that I was making and not understanding, I was not understanding as they were wrong since I switched height and width.



example1

example1

=========== Entry 6: =============



Date: 2025-03-06
Start Time: 09:00
Duration: 0.5 hours

I recommended to the team that we set up a to-do list with the remainder of the things that we need for the semester. I worked on thinking of firmware side things that we need and added them to the todo list.



example1

=========== Entry 5: =============



Date: 2025-03-05
Start Time: 17:00
Duration: 1.5 hours

I have been working on getting variable fonts set up. I am unable to test it as I am not in the lab. Right now I have grabbed a few different sized bitmap fonts from the linux kernel. I have also modified every UI/draw function to take in a font struct that stores the font array, height and width of the font. The draw_char function was modified to read these height and widths and use them instead of the hard coded values.


=========== Entry 4: =============



Date: 2025-03-03
Start Time: 16:00
Duration: 1.5 hours

Fixing .txt stuff in app. Right now we have the files named as .txt for some reason and the log files are also named with .txt, this means that our log files and others will show up on the list of decks to select from. We obviously don't want that so in the firmware we need to ONLY parse and display decks that don't end in .txt so that we can keep our log files with the .txt extension. Not having a file extension on the decks also allows us to have longer deck names and then we don't have to strip off the extension before displaying them.


We don't have this fully working yet, we only have it setup on the firmware side, need to set it up on the application side before actually enabling it.


Presentation work and practice.


=========== Entry 3: =============



Date: 2025-03-03
Start Time: 13:00
Duration: 1.5 hours

More presentation work, I have been doing the firmware slides mainly, software progress and prototyping progress stuff with Zoe.


=========== Entry 2: =============



Date: 2025-03-02
Start Time: 13:30
Duration: 1.5 hours

I am prepping for a demo video that we need to make for the presentation. I have currently added a counter showing which card you are on in the deck of flashcards and then also added bounds checking so you can't overflow the menu or the deck. I am also messing around with figuring out the best way to go back to the main menu or start downloading a deck. I tried adding a download option to the main menu but that isn't seeming like the best option.


Maybe we can add a whole separate menu in the beginning to download, go to settings, or view decks. Settings can include toggling a learning algorithm, randomization of decks etc.


=========== Entry 1: =============



Date: 2025-03-02
Start Time: 11:30
Duration: 1 hours

Design review presentation work


=============== Week 7 (9 hours): =================

=========== Entry 4: =============



Date: 2025-02-28
Start Time: 13:30
Duration: 3 hours

It doesn't seem like the MSI clock frequency is actually changing when I change it according to the reference manual. When I call the CMSIS SystemCoreClockUpdate() function the SystemCoreClock variable is still set to 4MHz when I am setting the MSI to 16MHz? Maybe this is why my timer delay was not working, it was assuming 16MHz. So I realized that by default the MSI clock range is taken from RCC_CSR and not RCC_CR. I do not know why both have an MSIRANGE field but I changed a bit in the RCC_CR to make the range be taken from RCC_CR, where I was setting it. This in turn fixed my delay issue too, along with refreshing the timer to make sure that the PSC and ARR are properly loaded.



example1

String wrapping isn't fully working. For short strings it is wrapping when it should not. Looks like I left remnants of centering in the wrapping function, this is not needed anymore because I have a whole centering function now. So it was trying to center twice which was causing shorter strings to be cut of way earlier than they should have.


Still running into some race conditions of sort when the buttons are pressed too often. Maybe we should move all rendering into the interrupts? I just don't like the idea of interrupts lasting a whole second each...


Now downloading a deck isn't working for some reason? I am confused... It is stuck in the loop reading the filename, so its never getting the delimiter.


Okay so this was a wild issue. As I said earlier the clock was actually at 4MHz and now its actually at 16MHz. I modified our UART config to be setup for 16MHz as for some reason it was configured for 4MHz before. So how our receiving works is that it reads in the filename and then afterwards reads the contents into a separate buffer. I declare two buffers, one for the filename and one for the file contents, I zero initialize both of these arrays. I was declaring the file contents buffer and zero initializing it in between receiving the filename and the file contents. For some reason when we were running at 4MHz this was working just fine. But after switching to 16MHz this somehow caused enough of a timing issue to throw things out of sync. If I move the declaration to before we start UART stuff or do not zero initialize it everything works fine. I bet the compiler generates a memset call or something similar. But I don't know why this would cause an issue with 16MHz and not 4MHz clock speed, if anything I would think it would be the opposite?


=========== Entry 3: =============



Date: 2025-02-26
Start Time: 15:30
Duration: 3 hours

It still isn't writing properly? It seems to be getting the EOF on the second character. We receive the first character of the file contents which is a '{', but after that nothing seems to be happening. I don't think it is staying inside of the loop so that means it must be receiving the EOF character (0x00 aka NULL).


File IO during UART is BAD. Even opening a file in the middle isn't working?? Okay so I figured out the problem. The way UART is setup on the sending side is that it just sends the entire payload at once, this is the filename plus the contents. The way we had this setup on the receiving side was to receive the filename, open that file and then read in 1024 byte chunks into a buffer and then write that buffer to the file upon it being filled. This will not work due to timing issues. We will get out of sync after even just opening the file due to how long file I/O takes. So we have two options: 1. Put the entire file on the wire at once and store this into a massive buffer on the receiving side to write to the file. This is the easiest option, but we need to see if we have enough RAM to do this with our largest files. I believe that we will. 2. The smart and efficient way is to send the file contents in 1024 byte chunks on the sending side and have the receiving side ACK these, once the ACK happens then the sending side will know its time to send another block of the payload. This just adds some complication and back and forth but is not too difficult to implement. And we would have ACKs t know if the device was actually receiving or not.


So now we are receiving but its not writing to the file? Turns out I was not closing the file... I completely forgot to do this.


Now the back button is not working. Weird because I thought it worked on PA2 before? It is weird, we probed the pin and it is ALWAYS high, even when we remove any stimulus to it. This is even more weird as this is an INPUT pin? Maybe its conflicting because its UART_TX? But we aren't doing anything with TX.


=========== Entry 2: =============



Date: 2025-02-25
Start Time: 16:30
Duration: 1 hour

I am working on cleaning up the codebase a bit as it has gotten a bit messy from a lot of quick prototyping. Mainly modifying UI stuff and making sure I am following some standard. For example, the drawing header function should not be called inside of *some* other drawing functions (such as main menu or flashcard) like I had it, I either need to do in all of them or in none. I am going with in none as there are other times where the header needs to be manually drawn at times (this may change).


For some reason we are unable to open the file for writing. I was not null terminating the filename. When reading it in we are reading into a buffer that is the max possible filename length but it may not actually be this long of course, I into a buffer that is the max possible filename length but it may not actually be this long of course, I into a buffer that is the max possible filename length but it may not actually be this long of course, I into a buffer that is the max possible filename length but it may not actually be this long of course, I had forgotten to add a null terminating character to the end.


Now we can't even receive the data properly? It doesn't seem like we are getting anything after the filename?


=========== Entry 1: =============



Date: 2025-02-24
Start Time: 13:30
Duration: 2 hours

I have been talking with Zoe about starting to get file transfer working between the PC application and the device. I have written up what comments that explain what the receive side should look like. We will first disable interrupts as nothing else can happen while we are downloading a deck, then we will receive the decks name and then a delimiter. After this we will read in the file contents until we get some sort of EOF flag. Then once everything is read we will store it to a file on the SD card.


I wrote this up, we are using ESC (0xBC) as the delim between the filename and contents and NULL (0x00) as our EOF. This was fairly simple as I just implemented what I described above, no majors issues thus far. I was able to print what we received onto the display and it *looks* right. We have not tested to make sure that it is actually writing to the SD card properly and that it can be parsed properly yet.


=============== Week 6 (8.5 hours): =================

=========== Entry 6: =============



Date: 2025-02-21
Start Time: 14:30
Duration: 3 hours

So Zoe and I are meeting up to get started on integrating the sd card and eink display. Right now I have just been hardcoding stuff for testing, now we can read and parse flashcard decks from the sd card to put on the display.


Merging both branches to main and then creating a new branch from that, luckily no conflicts because we were both working on completely separate subsystems.


So Zoe wrote most of the functions to read from the SD card and parse them properly into our deck structure. Looks like we do not have a function that we can easily call to be able to get all of the files. We just wrote one it is fairly simple as all of the files are in one directory, it just loops through all of the files in a directory and writes them to an array.


For some reason the array is not actually getting filled though? We don't need to pass the address of the array since they decay to pointers, not really sure what is going on here.


Okay so it turns out I was doing char* decks[NUM_DECKS] instead of char decks[NUM_DECKS][LEN_DECK_NAME]... So it was unallocated memory, this was a very silly mistake.


Wrap strings on flashcards in center can do this with strlen floor division. width to determine number of wraps to determine what line to start/end at. This works for centering horizontally, but I am having trouble centering them width wise. Okay that actually wasn't that hard, I just need to subtract the max width from the width of the string and divide by two, and if its very long and will wrap then we just leave it alone and only wrap horizontally.



example1

=========== Entry 5: =============



Date: 2025-02-21
Start Time: 12:15
Duration: 2 hours

I setup the clock to be 16MHz. By default the MSI is set to be 4MHz and that is a bit too slow for us with reading from the SD card and things of that sort, so I increased this to 4MHz. I also just finished setting up an actual delay system. Before I was just having a while loop decrement a variable but now I have setup TIM2 to be in a sort of free counting mode. We can just compare the current CNT with the CNT from the start. I found out that setting ARR to 0xFFFFFFFF is the best option as it will keep counting up for a very long time.


I just finished implementing scrolling on the main menu. The main menu can display up to 6 decks of cards, but if there are more than 6 decks we need to go to the next page. I implemented this by just changing the offset into what is displayed by checking if current selected deck on the menu goes above a multiple of the max decks per page (6), so basically floor division.


=========== Entry 4: =============



Date: 2025-02-20
Start Time: 13:15
Duration: 1 hour

I am going to start looking over and reviewing our schematics as there was some things missing on them previously, want to make sure there isn't anything else important missing.


Schematics look great so far, only a few small issues such as not grounding the programming header, I think Mark and Hannah will be able to get started on the PCB layout soon!


So for some reason PB7 isn't working for the backwards/down button? I have switched select to PB0 and forwards/up to PB6 so that I don't interfere with Zoes SD card pinouts so that we can try integrating our stuff together tomorrow. I have no idea why PB7 specifically wouldn't be working? Could it have something to do with the shared interrupt handler? I should probably test some other button in the 5-9 handler to see if it causes issues too.


=========== Entry 3: =============



Date: 2025-02-20
Start Time: 11:00
Duration: 1 hour

Spent time looking over the software formalization document, leaving comments and making edits.


=========== Entry 2: =============



Date: 2025-02-16
Start Time: 18:00
Duration: 2 hours

Right now I am working on getting menu selection fully working. For some reason when I try to select a deck from the menu it will re-render the main menu upon the button press but update the internal state for the flashcard navigation? This must be a race condition with the state machine?


After some messing around I added a 10ms delay between each loop of the state machine logic. There is no need for it to run that much anyways, this should hopefully give the inputs time to settle before rendering.


I was thinking about the best way to go back to the main menu with only three buttons. After talking with Hannah, mid conversation I realized that for a long press if the button goes low quickly while waiting (like a single press) then it can just move on. Unlike a double press where you have to wait the whole duration of the delay to make sure there isn't another press. So we will go with long pressing the button to go back.


Also I am starting to wonder where we should display stats such as the number of cards in the deck and things like that, right now I just go straight from the selection menu to the first flashcard, no place for seeing stats, do we need this?


=========== Entry 1: =============



Date: 2025-02-15
Start Time: 15:00
Duration: 1 hour

I have been experimenting with how long drawing to the framebuffer takes. Obviously rendering is the longest part, but this can happen independent of the CPU. We can have DMA write the data over SPI and then the e-ink does rendering on its own after that. Therefore we could use that time to predraw the next framebuffer so the only perceived delay to the user is the actual render. I am unsure if this is possible as of now but I am still looking into it.


I got multiple buttons setup. I am as of now able to move both ways through the menu and select a deck of cards, now need to get the info from the SD card and see how we are going to have it formatted.


=============== Week 5 (8 hours): =================

=========== Entry 3: =============



Date: 2025-02-14
Start Time: 21:00
Duration: 2 hour

I want to figure out how to speed up rendering stuff even more. I think that I can do some sort of double buffering, basically load up what would be in the next buffer early and render that one next? I am unsure if I can know what would be in that buffer though, but that would make it so that I don't have to wait until the write to the framebuffer is done to start the render. I am not even sure if writing to the framebuffer early will even help, maybe it is not not that slow of an operation?


I haven't really been looking into this part too much, I will look into it more a later time as it isn't super important. As of now I am working on rendering the flashcards and wrapping text. Wrapping text is annoying because I have to wrap based on the word, just wrapping around the screen based on characters is simple, but not as simple for words.

=========== Entry 2: =============



Date: 2025-02-13
Start Time: 15:30
Duration: 3 hour

I have been working on getting pinouts organized for our prototyping dev board to make sure that everyone is using different pins so that we can start to integrate easily. Because SPI3 uses the GPIO pins that I was using for buttons I need to switch. Some free pins that I can use are PB0, PB6 and PB7. But for some reason when I try to switch to these pins everything stops working? The only thing I change is my button_init() function and now even SPI doesn't seem to be working as I can't write to the display.



example1

My e-ink pins are all on Port A so I am unsure why this could even be impacting anything?

=========== Entry 1: =============



Date: 2025-02-11
Start Time: 13:30
Duration: 3 hour

I have been doing a lot of thinking about how to handle button presses. So far I have setup EXTI interrupts and am testing navigating through the menu, but this doesn't seem to be the best way to do things. If the user presses multiple buttons back to back and the display renders after one, then either multiple renders would need be to queued up or the display would not be displaying the correct info. Both of these are bad, pressing the button multiple times should not need multiple renders if it happens relatively fast. Also if the user has to wait until the screen rerenders to navigate down another menu option again, that will take a long time to navigate their decks if they have multiple decks stored on the device.


The only real way to avoid any race conditions between the internal state and what is shown on the display is to halt all button presses during a refresh. But then the problem comes up of how many button presses can happen before a refresh so that we can allow multiple. Or I need to come up with another menu, or add partial refresh support.


Okay so for now I set up the fastest refresh mode, this will make refreshes take ~1 second. This will solve a decent amount of the problem. Right now I only have button presses actually do anything if the display is NOT rendering. Therefore the user can spam the button all they want but it will not cause race conditions. I basically just a mutex that is checked in the interrupt handler, if its not set then the handler will take it and it can only be cleared once the rendering is completed (all commands are sent and then wait the 1 second it takes to complete the render.)

=============== Week 4 (10.5 hours): =================

=========== Entry 6: =============



Date: 2025-02-05
Start Time: 14:30
Duration: 3 hour

For some reason when I try to draw a line or something below ~160 on the y axis it breaks and wraps around back to y = 0 and then also shifts over by some x offset? I am unsure of what is going on with that as of now.


So the issue was just that I was calculating the index in a 16 bit integer and the value can be upwards of 120,000, so it was just cutting the top half off, which makes sense based on where it was failing to draw below.


I also got UI stuff setup. The ability to draw text within rectangles and have it centered and things of this sort, this will be necessary for making the main menu and things of that sort.




=========== Entry 5: =============



Date: 2025-02-05
Start Time: 10:30
Duration: 1 hour

I got font rendering working! I found a good 8x8 bitmap font which is exactly what we want and then the algorithm to render this font. The algorithm is very simple, you just need to select the 8 bytes corresponding to the character (the array is setup in a way so you can just index by the ASCII value) and then iterate over the x and y components of the 8x8 character and check each bit of those 8 bytes to determine what pixels need to be turned on.
example1


=========== Entry 4: =============



Date: 2025-02-04
Start Time: 14:20
Duration: 2 hours

Uhh good news, its kind of working? I can sort of clear and write but its still a bit scrambled, but its not just random anymore. So apparently the DR register is 16 bits and if you write less than or equal to 8 bits then it will pad the other byte with 0's. I had no idea this was the case and ended up finding a forum post that led me in the right direction along with reading through a large portion of the SPI section of the MCU data sheet. This took way too long to figure out. I noticed it because on the AD2 logs and on the scope it was showing something like: 0x12, 0x00 when just sending 0x12 and it was not doing this on the Arduino.



example1

But now its almost like the burn in is getting worse when using it with the STM but then mostly goes away when I clear it again with the Arduino? When the STM is flickering to refresh the whole screen does not go black, only a scrambled pattern. Therefore it doesn't seem like its refreshing the whole screen for some reason. Some pixels do seem damaged unfortunately...


So the display is slightly damaged but it should not be a problem for now, very slight burn in.


BUT I GOT IT WORKING. Zoe found a GitHub that sends command 0x71 in the BUSY wait function, this command is not in the datasheet. It is something about getting the busy status? But we can't read so I have no idea what it does, I can find no documentation on it. But sending this command in the BUSY wait function somehow fixes the rest of the non-SPI related problems? I may reach out to Waveshare regarding this.


=========== Entry 3: =============



Date: 2025-02-04
Start Time: 11:15
Duration: 2.25 hours

I added a delay between the transmissions for sending data and I am able to read all 15000 0xFF's being sent on both the STM and Arduino. So all of the data is actually going across. Even with the delay in place the data is still scrambled though.


It looks like if I send the command 0x24 which tells it to start writing to RAM and then don't send data on the arduino that it ends up writing garbage like the STM does. But on the STM when I didn't send data nothing happened at all? On the arduino I can send partial data, lets say 3000/15000 0xFF's and then part of the screen will clear and the rest will be nonsense. But on the STM it doesn't seem like I can do this? It almost seems like none of the data is actually going into RAM.


This means the STM either is not receiving the 0x24, or it is not receiving the data afterwards. I do not know how to test this though because it looks like these values are going across the SPI bus. I am at a loss as of now.


DO NOT WRITE TO THE DISPLAY WITHOUT INITING IT FIRST. I THINK I CAUSED A BIT OF AFTERIMAGE/BURN IN!!


Looking at the scope for the Arduino waveforms there is a delay after command 0x12 before starting the rest of the init sequence, even if BUSY is active? How is this here? What is doing this? Also there is then a long delay (~30ms) between initialization and sending the 0x24 command and writing to the RAM. But there is no delay put in and I am holding BUSY idle. I tried hardcoding these delays into the STM and its still not working.


=========== Entry 2: =============



Date: 2025-02-03
Start Time: 17:30
Duration: 1 hours

I got the AD2 hooked up to the STM and the arduino and have recorded the data onto the lab computer. There is almost 2/3 less lines in the STM file, this may mean I am not writing enough data to the display RAM?


=========== Entry 1: =============



Date: 2025-02-03
Start Time: 11:45
Duration: 1.25 hours

Today I want to test possible other reasons why garbage is being displayed on the display. I hypothesize that another reason could be due to it not properly being reset. After testing it seems that not doing a reset just makes it so nothing happens with the display, so that is not a possible problem I don't believe. I checked on the STM as well and if I don't call the reset function nothing happens, therefore our reset should be working properly.


I am attempting to verify that the display is getting the command 0x24 which tells it to start writing to RAM. On the scope I cannot see the sequence starting with that, but I can see it ending with the sequence to turn on the display... I cannot seem to confirm this with the scope, I think I may need to get an AD2 or something of the sort and compare exactly what each is sending, not based on the code but based on what actually crossed the bus.


=============== Week 3 (20.5 hours): =================

=========== Entry 8: =============



Date: 2025-01-31
Start Time: 13:20
Duration: 3 hours

Lots of debugging.


So if I write to the RAM with the Arduino all works just fine. But then if I leave power to the display and move the connection over to the STM and ONLY init and turn the display on it scrambles the previous image. I do not understand because I did not put it to sleep, that means the RAM should be kept, so turning the display on would just render what the Arduino put into RAM. But like I said, it is still scrambling it. I do not understand what is happening. What is the point in RAM being saved during light sleep mode if we cannot re render what is in the RAM?


I should try to write to the RAM on the Arduino and then ONLY turn on the display without writing to the RAM and see what behavior occurs. Maybe the STM isn't actually writing to the RAM and is only turning on the display and that causes issues? I need to test this on the Arduino.


So simply turning on the display without writing to the RAM on the Arduino with whatever the STM32 wrote to RAM seems to also just keep scrambling it.


And then I just wrote to the RAM with the Arduino to make the screen look nice, then I ONLY turned on the display and did not write to it with the Arduino, this also resulted in the same behavior, a scrambled image.


example1

THIS MEANS THAT THE STM32 IS NOT WRITING TO RAM AND IS ONLY TURNING ON THE DISPLAY. Or it is somehow turning on the display before writing even though I am not doing that?

=========== Entry 7: =============



Date: 2025-01-31
Start Time: 11:00
Duration: 2 hours

I wrote the data structures section of the A3 document.


So I got the display to work, sort of. As of now the screen is just "scrambled", its just random data on the display when I try to clear it. There were a few problems that I resolved from before.


First thing is that the BUSY pin is NOT ACTIVE LOW. I do not know how I messed this up so many times, the datasheet said to WAIT until BUSY goes LOW before sending other commands, I misinterpreted that. So the whole time the display was actually ready and I had thought that it was busy. I also was playing around with some SPI settings but I am unsure if any of them actually did the trick. I may experiment to find out which one it was.


Second thing was that I was not actually writing to the display. I figured that it you gave the initialization commands to the display that there would be some visual feedback but it turns out that there is none unless you actually execute the command to update/render the RAM onto the display.


I also learned From Shivm that we need to set the coupling mode to normal on the scope when doing SPI mode for it to properly trigger and save the data.


=========== Entry 6: =============



Date: 2025-01-30
Start Time: 13:30
Duration: 3.5 hours

The first thing I started with was being able to see the SPI signals on the scope. Yesterday the CS was not even going low unless stepping through with a debugger meaning a timing issue. I realized that I was not simulating a real life scenario as I did not have the timing delay in the correct place between putting the CS low and then high. I switched to using my eink SPI functions and that fixed that issue, this waits for TXE to go low, which is enough of a delay.


After this I was seeing data on the scope but the data was not correct. Turns out that scope wants the clock polarity bit to be high, which is not SPI MODE 0 like the display uses. Doing this allowed me to see the correct data, although I need to figure out how to put the scope into SPI MODE 0 so that we can view the SPI data as we send it over to the display.


example1

Even with SPI seemingly working the e-ink display's BUSY pin is still constantly high, right from power on. I looked into the Waveshare code to see how their SPI is configured and it seems to be the same as mine. Spent a lot of time debugging and no solution. Next step is to run their Arduino demo code and make sure that it is not a hardware/wiring issue.


It works with Arduino!


example1

=========== Entry 5: =============



Date: 2025-01-29
Start Time: 14:30
Duration: 4 hours

I spent time looking over flowcharts that Zoe made for the A3 document. I also spent time talking to Mark, Hannah and the Professor about what exactly constitutes a PSDR. For example the display we purchased comes on a PCB that has some extra circuitry on it. I would have believed this to be a "module", which we were told we should not be using. But the Professor said that the e-ink display PCB would be a whole project on its own so we can use the module. I don't know that much about hardware, but from what I do know I disagree (although he did mention possible layout issues and I know nothing about PCB layout, but the layout on the PCB we have looks fairly simple?). This helps us out significantly and takes away what could end up being a lot of work.


In man lab we received our e-ink display. This is great news as I am able to start prototyping and testing out my e-ink driver. Hannah soldered some leads onto the PCB and I hooked it up to my STM32L4 development board. After testing my code I found some small errors such as pins being set to the wrong type and accidentally putting both the RESET pin and the MOSI pin onto the same pin.


Currently the e-ink display is constantly busy, the BUSY pin is always active. According to the wiki this is probably because the SPI is improperly setup or because I have the pins hooked up incorrectly.


I attempted to view the SPI signals on a scope but they are acting weird, also in a single SPI frame it is not looking like CS is going low even though I am setting it low and then back to high, I am unsure what is going on with that.

=========== Entry 4: =============



Date: 2025-01-29
Start Time: 10:00
Duration: 2 hours

I worked on section 1 of the A3 document. We were told to not reiterate anything written in that document here, so feel free to check out the document as it is linked on our website. Part of this included research into battery voltage monitoring and asking Mark and Hannah as I did not know anything about that.

=========== Entry 3: =============



Date: 2025-01-28
Start Time: 15:00
Duration: 2 hours

So based on what I ended up being able to find on the Waveshare website, the pictures of the product we bought show that it is V2.2, therefore the initialization code I wrote previously may be wrong as it was for V1, I also found the V2 datasheet hidden on Waveshares website under their wiki for the display. So I ended up rewriting the initialization code using the below flow chart (INSERT PICTURE) and Waveshares example code. Although there are a few things wrong with the datasheet, for example they say to send the data in the wrong order for setting the Y-axis RAM address. (INSERT PICTURE OF MY CODE HERE).


example1

example1

During this time I also started adding functions for drawing pixels and handling the framebuffer. So since this display is just black and white we are able to represent each pixel as a single bit instead of a whole byte, this is very helpful since we are on an embedded device with limited memory, this is 8x more memory efficient. This means we just need a little bit more logic to handle this. As with any linear framebuffer, we can find the index into the framebuffer with `y * WIDTH + x`. As you can imagine we just have to divide this index by 8 and then use `x % 8` to find the offset into the byte.

=========== Entry 2: =============



Date: 2025-01-28
Start Time: 10:30
Duration: 2 hours

I started today by setting up the firmware part of out GitHub repo. (insert picture of repo on browser here). In this repo I initialized a platformIO project, this is the same tool that we use in 362 for building, running and debugging our code. This is going to make things significantly easier for us than writing all of the startup code manually, this saves hassle of debugging startup code and allows us to focus on more important things.


Next I moved on to writing the first code for the repo. I started with a simple SPI interface that can be used for any SPI peripheral, this will get us set up to write the e-ink driver and the SD card driver. This opens up rx and tx functions and also initalizes the SPI peripheral for the e-ink display. As of now I am unsure what clock frequency I should run the SPI at, I will experiment with different ones once we have the hardware. For now I have it set to 2MHz.


I started writing the e-ink driver. This driver has the following extra pins besides SPI ones: - BUSY - D/C - RESET So BUSY pin is pulled low when the display is currently doing an operation that should not be interrupted, this is important so the driver can wait before executing the next command. The D/C pin allows us to tell the display if the data that we are sending it over SPI is data or a command. There is also the option to use 9-bit SPI and specify it that way, this is decided with the BS1 pin (pulled low for 4-wire SPI).


As of now I am unsure if the display we have is V1 or V2. Waveshare does not allow you to select which one we are purchasing and the only mention of V2 is saying that it allows a faster full refresh. Also I do not see any mention of V2 in the datasheet.


To set up the initialization of the display I am going through the flow chart shown below and some example code put out by Waveshare. I will not list out all of the steps here but the datasheet is linked on our website and the steps are shown in the screenshot below. I implemented all of this into the e-ink driver today.


example1

=========== Entry 1: =============



Date: 2025-01-26
Start Time: 12:00
Duration: 2 hours

Helped Zoe with debugging SD card. Found 3.3v not on rail to fix one issue, still have physical drive error


I helped Zoe with debugging the ECE 36200 SD card module. The code was completeling hanging when trying to mount the SD card. We then started stepping through the code to try to find the source of the error. We found that it was failing in the initialization sequence (I would insert a screenshot but I do not have the code on my computer). Sometimes the 362 dev boards only output ~3V, we ended up finding out that this was the issue, the sd card reader required 3.3V and even this small deviation caused the issue. After this a new issue acme up and this one printed the error string "Physical drive cannot work". We did not have enough time to continue debugging so the source of this is still unknown. We need to get this working as all SD card readers use a common protocol, so even if we are using the SD card reader from 362 for prototyping, we can easily buy another module and the code *should* still work.

=============== Week 2: =================

=========== Entry 4: =============



Date: 2025-01-24
Start Time: 12:00
Duration: 2 hours

Today I spent time touching up my journals and posting them onto the website.

I also worked on the A2 functional description document. I finished up the part I was working on which was the computational constraints. Some of the lower level details of the constraints will need to be ironed out once we know exactly what metadata will be stored etc. But for now they are sufficient. We should not need to worry too much as we are choosing an MCU with ample RAM and will be using an SD card for persistent storage which will have plentiful space.


I also assisted Mark with the section on power. I spent some time writing a python script which did power calculations to see how long the device will last. Very rough calculations on my end show ~140 days while Marks were showing ~50 days, although that was with a different MCU standby current. Although our calculations are not assuming other hardware besides the display and MCU as of now, also they are not taking into account power losses from regulators or anything of that sort. These calculations are important as one of the selling points of our device is long battery life, the goal is to not have to worry about charging it often so it can just stay in the users backpack to be able to study whenever.


example1

=========== Entry 3: =============



Date: 2025-01-23
Start Time: 11:30
Duration: 4 hours

Today I have been spending time reading through more code that people have written for e-ink display drivers and their write-ups on it. Since we need to get prototyping ASAP I have been doing some reading so that we can be prepared when the display arrives. this article has been helpful, especially because it linked to this Github repo which is going to be a big help as it is some example firmware for a different MCU directly from Waveshare (the manufacture of the e-ink display we are buying) themselves! I have yet to look into this code but will hopefully find time to do that soon.


I also have been looking through the A2 Functional Specification document and making some slight tweaks before we get ready to submit it. The team has been doing great work thus far!


In the afternoon I spent some time helping Mark with understanding part of the hardware schematic for the e-ink display. He found out that the main driver circuitry needed has to do with boosting voltages. We were confused about driving the gate of the transistor used in boosting. I looked into this and found that we do not have to drive the gate of the transistor, this is done by an internal display controller in the device. This makes things significantly easier than we had previously thought. We thought that we would have to deal with waveform (wbf) files and manually controlling the display waveforms. Luckily displays have these controllers in them that do that for us and we have to supply the correct voltages in hardware and then do the initialization sequence and then push the framebuffer in software. We are also hoping to support partial refresh in the firmware since our display supports that.


example1

I spent some time updating our website. I updated our PSDRs, although our software one(s) are not final. I also uploaded our microcontroller datasheet and reference manual.

=========== Entry 2: =============



Date: 2025-01-22
Start Time: 15:30
Duration: 2 hours

During our man-lab session I recommended that we use the STM32L4 line of microcontrollers as it will give us a mix of the processing power we need along with a low energy usage, especially while in standby. It seems that we are going to go with the STM32L496 as this is the one with the most SRAM which will be helpful for storing numerous flashcards in memory at once as well as the e-ink framebuffer.


example1

During this session I also recommended that we go with Waveshare e-ink displays as I have seen and considered using one before for a personal project. They seem to have decent documentation and are easily purchasable on their website. We collectively decided on a 4.2 inch display. First Zoe and I need to have a board that comes with a hardware driver so we can begin prototyping the firmware and then later we can buy the raw display to end up in the final product.

Entry 1: -----------------------------------------------------------------

Date: 2025-01-21
Start Time: 11:00
Duration: 2 hours

I spent more time today looking into the microcontrollers. I was discussing the differences that I found previously with my teammates and after some discussion we decided on going with the STM32 over ESP32. During this discussion we talked about how many open source projects we were looking at were using ESP32 but that we did not need the wireless connectivity, therefore the extra power draw is not worth it.


I also spent some time researching the basics of e-ink displays and reading articles sent by other members of the team as well. We were looking into some open source hardware drivers for e-ink displays to understand how we can go about designing our own. I was also looking into software implementations of e-ink drivers to get some ideas. One example I found is here as well as some more general e-ink driving documentation such as here, this includes algorithms for rendering fonts, drawing lines etc.

=============== Week 1: =================

Entry 3: -----------------------------------------------------------------

Date: 2025-01-17
Start Time: 19:00
Duration: 2 hours

I have been looking into ESP32 vs STM32. The power draw alone is a massive difference that will be a big deal to us since we want a long battery life. In deep sleep mode with only RTC enabled (I am discussing with RTC enabled so that we can keep system time in case we need to implement reminders for studying) the STM32L4 series only uses 0.28µA while ESP32 uses 5µA, that is almost 18x more current. When running the ESP32 says it uses at a minimum 27mA at 160MHz which is 0.16mA/MHz while the STM32L4 uses 0.084mA/MHz, so that is about a 2x difference.


Therefore if the device was used for 2 hours everyday and was in sleep mode for 22 hours the STM32 would use ~13.44 mAh/day at 80MHz while the ESP32 would use ~54.11mAh/day, so the ESP uses ~4x more energy.


Everything else besides this seems to be in favor of the ESP32. They have 4-6x the SRAM and flash, are faster and have native wireless connectivity if we decided to go wireless for sending the flashcards to the device

Entry 2: -----------------------------------------------------------------

Date: 2025-01-16
Start Time: 16:30
Duration: 1 hours

I spent time working on filling out and getting the website setup. I navigated through the structure to get a good feel of things that we need to update now and in the future. I updated all of my sections as well as went through and edited other parts such as adding out GitHub.

Entry 1: -----------------------------------------------------------------

Date: 2025-01-15
Start Time: 15:30
Duration: 2 hours

I spent the time in class working on getting the website up and running with the rest of my team. I was having problems on my end with getting the network drive mounted on my Linux system. Originally I was trying to use sshfs as that is what I use for mounting my eceprog account to my local system so I can use my local text editor but this was not working. I found out that I have to use CIFS with the normal UNIX mount.


example1

During this day I also spent time working on the A1 final project document. I worked on my personal portion of it, filling out what parts I am working on as well as writing the description about myself.