Reading Timer
I really like reading. Like, a whole lot. If I’m not careful, I will easily eat up 4 hours straight of reading. Alas, my body isn’t so happy with that. Between headaches from eye strain and my back being sore, I really need to take breaks when reading. While I considered getting a pomodoro timer for my phone, that’s not a great thing to put on the ultimate distraction device. Instead I wanted to make my own timer, and at the same time make it work for my migraines. Recent advances in migraine science have shown that certain green wavelengths (520nm) can help sooth the light sensitivity that comes with migraine (https://pubmed.ncbi.nlm.nih.gov/32903062/), so that was going to be my only source of light.
Demo
The device has 3 buttons:
- Reset
- Add a minute
- Pause/Unpause
Timelapse showing 21 minute countdown. The lights flash at the end, perfectly out of sync with the timelapse.
And the flashing.
Parts
I wanted this device to be battery powered, my first such device. That influenced the part selection.
MCU
I normally use the ESP32 for most of my projects. But it really didn’t fit the requirements here so I took the opportunity to start learning the STM32 line.
I ended up selecting the STM32F031K6T6. I think it was the cheapest I could find. Unfortunately that was a little shortsighted. I wanted to put the chip into deep sleep and use the RTC to wake it up periodically. Looks like that’s not supported with this chip running off the internal oscillator. I chose an alternative strategy of lowering the clock rate significantly to reduce battery consumption and that worked well.
Regulator
I’ve always used Low Dropout Regulators, simple, straightforward, power hungry. This time I went with the Analog Devices ADP2108 switching regulator. It was on the list in The Art of Electronics and didn’t require additional extra parts to set the output voltage. It was spendy, actually costing more than the MCU! If I ever go to production with this I’ll be using a different converter as my power requirements ended up much lower than I expected.
The converter was hard to use. My first board layout suffered from too much noise and the converter would occasionally fail to start. This took a long time to explore and figure out what was going on. After staring at the sample board layout extensively I redid the PCB layout and it worked the second time around. No more false starts.
LEDs
I selected the Würth Elektronik 150080GS75000. These are 0805 SMD parts with the best spectral distribution I could find at Digikey.
Latches
I needed to turn on/off 13 LEDs with my design. While many solutions would use a swept approach to reduce part count, that would add flickering to the LEDs. I wanted to avoid that at all costs. I selected the PCF8574ADWR from TI. It’s an I2C 8 bit port expander. It did take careful reading of the data sheet to realize you need some extra resistors to reduce power consumption when an LED is turned off.
Power Consumption
One side effect of using a buck converter I didn’t think about was the electrical noise. Oh my, so noisy. This normally wouldn’t be a problem, but I wanted to use a Current Ranger to measure the current. It was absolutely useless because of noise. In the end I unsoldered the regulator, bridged it, and then used a linear lab power supply to feed the board so I could measure the current.
In the end putting the chip into deep sleep saved 360 microamps. That’s what I’m measuring here, but ended up not using. I couldn’t figure out what was drawing 1mA. It may have been because I hadn’t populated all the current limiting LEDs needed for the I2C latches.
Schematics
Oopsies
I managed to:
- Forget to wire up power sense on the programming port (misunderstood how to use it)
- Used the bottom button for a hard reset (pulling NRST low). I actaully wanted a soft button in the end.
- Bypass the Buck converter so I could use the Current Ranger
- Didn’t bring out any pins for easy oscilloscope or logic analyzer hook up. I added a pads for the UART, ground, VBAT, and +3.3 in the second rev. I2C has easy pickup on R27 and R28 so didn’t bother there.
- Those I2C traces are long and parallel. There is a fair amount of crosstalk, but doesn’t seem to cause a problem. Given that I have a ground plane on the other side of the board I can probably move those traces even closer together :). Stack Exchange
Design
Nothing real special here.
The PCB layout was a bear for the buck converter. I did not keep a copy of the bad version.
AI for Embedded
Given that this was a new chip to me I decided to try and use Cursor to help out. Overall it gets a C for effort. Here are the many places where it led me astray.
RTC WakeUp
Now to be fair, the documentation on this is really poor. I started out my implementation of one second interrupts by using the alarm functionality of the RTC, and then in the ISR resetting the alarm for one second in the future. I took this from STM reference documentation.
It did not work reliably.
More RTC
So I asked Cursor for help, and it pointed out that I should be using the rtc wakeup functionality. I spent hours trying to get that enabled in STM32CubeMX. The controls would never show. I had Cursor tryout different things in the code to workaround it, never succeeded. Finally I did my own research to learn that STM32F0 part line doesn’t seem to support it, at least not with the internal oscillator.
SysTick wrong
I then asked for help with using the SysTick() approach. SysTick() fires every ms, so I needed it to count to 1000 and then call my clock tick. Cursor was happy to write me code, code that looked correct, but code that didn’t work at all. I asked it to troubleshoot itself, it couldn’t figure out what was going wrong but kept reassuring me that it was working. I went and did some research, to find out that STM removed the approach that Cursor was doing with V5 of the HAL. Mind you, this was very deep inside of a forum, and was a casual response from an STM employee in regards to other people complaining their code had broken after upgrading to version five of the SDK. Keep in mind v5 was released in 2019. My code is on v6…
Just a plain timer
I went over to STMCubeMX and provisioned one of the simple timers for my use. I generated code and then went back to cursor for help. I told it to use the timer I had just provisioned to generate a one second call back. It did a good job of reading the generated code, figuring out the clock speed, the appropriate pre-scaler, and setting up all the constants for me so that I got a one second call back into my code.
Summary of AI
Sort of a mixed bag. It did some basic routine stuff for me very well, like dealing with the prescaler math. But lead me down the wrong path for several other things. But once I decided to use a timer, it was able to do the timer implementation in seconds and I didn’t have to struggle through the documentation.
Conclusion
This was another fun project. I’m not sure how much the green lights really help with migraine, I’ve had a dedicated commercial lamp using those for years that I never use. I still need to work on the packaging somewhat, I’m unhappy with the layout of the cover, but I want to sit down and use it for a while before I make a decision on what to do there.