2-4-25

It's been a while, hasn't it?

In the 2+ weeks since my last note, I have gotten to the point where the ePaper display successfully updates with the next step on power up. All that is left to complete what I had originally planned as phase two is to add noise collection for RNG seeding and a RTC-based sleep and wake.

Part of the reason this update is so late in arriving is that I put off even trying out my new code because I did not look forward to fixing the inevitable errors with it. There was a fair share of errors, but in the end it only took about a week to a week and a half to get things working. This delay means that I will not be able to actually give out PCB business card at the career fair, now less than a week away. I still plan to show off the progress that I have made, as the internships I would be applying for would probably be more firmware side anyways.

I want to go through the process from the first try to the current state of the project. Lots of the specifics have probably slipped my mind at this point, but I will try my best to recall the process.

Fixing Software

At some point I set up my ePaper display and Launchpad again and tested out my new code for the first time. Unsurprisingly, it didn't work the first try. I used MSPDebug to try and figure out where the program was going wrong. I ended up seeing behavior similar to when I was first getting started with the Launchpad and the watchdog timer was resetting the board (see here). My code would jump back, seemingly for no reason, to code near the main method of the program. After poking around for a while, I realized that my interrupt handlers were not being pointed to from the interrupt table. I was trying to export the function directly to the interrupt handler section, when I really needed to export a function pointer to that section. This was the first issue I fixed to get the software on the board to run correctly.

Based on commit history and what I can remember, I was still running into a reset issue. To fix this, I tried placing infinite spin loops at various points in my code to see if the processor reached them or not. I believe I tracked down the issue to the SPI handler's behavior towards the end of execution. After looking through the SPI handler's code, I decided to add extra checks to ensure that zero length slices would never be accessed. After this, I believe my code ran to the postUpdate() function, but the display was still not updating.

Cooperating with Hardware

At this point, I was wondering why my board was seemingly sending over all of the correct data to the display yet not causing it to update. At some point I ended up deploying Waveshare's example code for the display to an Arduino Uno I got for one of my classes to test out the display, which did work. Now that I knew that the display wasn't fried, I went back to seeing what was wrong with the Launchpad setup.

At some point in this whole debugging process, even if not exactly here, I discovered that at least one pin was not connected correctly. Until that point, there is no way my code could have worked. I remember realizing that the reset line from the display was connected to the literal (CPU) reset pin on the Launchpad instead of its proper digital I/O. Even after correcting this, the code still did not work.

At this point I assumed some sort of error in setting up the display. I did two things to try and resolve this. The first was to enable the eUSCI's clock divider to slow down the clock to 1MHz. The original 2MHz was towards the upper limit of what the board could handle, so slowing it down might have helped with timing issues and noise from the long wires on the display connector. The second was to switch from pushing new data on the TX interrupt to pushing new data on the RX interrupt. This is so that the chip select line is deselected in between bytes. This is recommended by the display driver's datasheet. This inspiration mainly came from a TI E2E form post that explained that:

  • SPI is always transmitting and receiving, even if one of those is junk data
  • the receive interrupt is equivalent to transmission being completely done
    But even after this change the code still didn't work...until I set a breakpoint in some of the code dealing with waiting for the reset signal.
    first_img.jpg
    This was something I had been looking forward to for a while. It came in such an unexpected place too. However, needing a debugger attached to make your program work is not the best look, so the next order of business was to try and make it work without needing a debugger. I went from a variety of theories on what was causing the behavior. Here is a rough order:
  1. Setting a breakpoint causes the display to work
  2. Resetting the board using the debugger causes the display to work.
  3. Resetting the board without power cycling the display causes the display to work
  4. Resetting the board while the display is powered, even after a power cycle, causes the display to work.
  5. Back to three?
  6. I don't know anymore...
    After taking a look at the reset signal with an oscilloscope, I saw that the busy signal would not trigger at all (or for very small amounts of time) when the display failed to refresh. However, this was not an error in sending data, as I had gotten the display to refresh before. My current guess as to what was wrong with the display is that the driver chip is very particular about its startup sequence and resetting the board must have had some effect on the chip that made it work. My solution was basically to perform a reset myself in code. Not of the whole program, but just the driver chip. I duplicated the startup sequence code, and also adjusted all of the busy waits (which probably do not help either) to their minimum time. Amazingly, this seems to work. Plugging in the board from a cold start successfully steps the program. In fact, I may have broken the program when resetting from the debugger. However, using LPM3.5 is essentially a cold start for the CPU. If this is the case it will hopefully not be a huge problem.

Next Steps

I will need to finish up the last few features, but after that I will be done with what was originally Stage 2 on my project outline. I will also start writing up more proper technical details for potential employers to look over. I should also go back through my code and make sure it is well commented.

The hardest part of this will be getting everything into a semi-presentable form. What I may do is get the program to work on the MSP430FR2476 board. This is because it has a coin cell battery holder and because I don't mind permanently soldering wires to it as the code runs just fine on the MSP430FR2433 board. There's a very small chance that I make a 3D printed enclosure for this, but I'm no mechanical engineer and time is tight.

There is also the issue that the build script for this program does not download TI's libmsp430.so driver for MSPDebug, and does not work correctly on Windows or Mac. I may fix the issue for Linux, and maybe Windows if time allows, but this is low on my priority list at the moment.

I also need to make sure that this project gets uploaded to GitHub and that the people I talk to have a means to get the code and documentation (if you are reading this, it worked).