Project: ARM11 & Raspberry Pi Smart Mirror

Project: ARM11 & Raspberry Pi Smart Mirror

During my first year of college, I have had multiple occasions to work in a team on a big scale project. One of the projects I am most proud of was one on which I have worked near the end of my first year.

We have been asked to write, from scratch, an emulator and an assembler for a processor of type ARM11, write an assembly program and set it up as a kernel for a Raspberry Pi to make the on-board LED blink, and then extend this project with something of our own, full creative liberty (as long as a great part of the project was done in C). For that, we have made our own version of the Raspberry Pi Smart Mirror, written (almost) entirely in C.

The ARM11 emulator & assembler

The first part of the project was building the emulator of the processor. The emulator would take as an argument a binary file, composed of assembled ARM11 instructions. It would have to read the file line by line (32 bits at a time) and, based on the instructions that the emulator would read, change its internal state (main memory, registers, flag bits). After reading the whole file, the emulator should output its final internal state.

When thinking back on it, I cannot believe that my team and I have started from scratch. The whole program got extremely complex at the end, and we have finished writing and debugging it in less than a week. I must admit, though, that most of our work was not coding, but discussing and organising the project overall.

Having started reading Clean Code recently (more on that book in the article above), I had an idea about working as a team in great length projects, with code that can be understood by everyone reading it.

First thing on which we have decided was the coding style. For reference, we have went for the Google Java Coding Style, with a few tweaks, as we would be working in a different language.

Second, we have thought about task management. For the project, we were asked to allow only 4 types of instructions: Data Processing, Multiply, Single Data Transfer and Branch instructions. As we were 4 team members, we have distributed these tasks evenly. To allow better self containment, each of us worked on a separate file, similarly to "classes" of instructions, with two main functions: decode<instruction> and execute<instruction>. This design would also be a great asset if we would ever want to add a new instruction type.

Third, to follow the DRY principle (don't repeat yourself), we have written a file with utility functions, which we have used mostly for the bitwise operations in order to hide their complexity. I have taken the liberty to write most of those functions before we all started to work on our separate instruction "classes", and I believe this improved our timing considerably. As an example, let us take an arbitrary instruction of type Single Data Transfer. This instruction, depending on some bits, it would either get some data from the main memory and move it into a register, or vice versa. By only knowing which bit were required, the function could not have been more specific: getBit(instruction, index). Of course, there is some bit manipulation under the hood, but now the programmer does not need to deal with it.

After finishing one of the instructions types (Branch, in our case), we have started working on the main emulator code. This one took a while, as I have insisted to use very strict naming conventions, but in the end, the code would become extremely easy to read. Just let me give you an example of the main function:

No alt text provided for this image

In retrospective, I maybe could have made some more changes for readability, but tell me if you don't get what this code is doing. I get the instructions the emulator needs to run from the file. These need to be stored inside the emulator's memory, so I use the first function to do that. Then, I run the actual emulation, and then I print the memory of the emulator. This is exactly what I said that the emulator had to do. Of course, only the util.c file has 300 lines of code, but still, the abstraction (in my opinion) could make even a non coder understand what is happening. I have tried enforcing these kinds of abstractions all over the project, with readable functions of small length. We would brainstorm the names of the functions more often than the algorithms that we would use!

Some people would say that we could have finished this project even faster if we would not have spent so much time naming and thinking about readability. I strongly disagree, and I will tell you why. We had a lot of bugs. Any project has a lot of bugs, especially team projects. The biggest issue in team projects is debugging. Good coders with different coding styles make for bad team mates. Usually, debugging code takes forever, because of the different components of different abstraction levels.

We have finished debugging the code in a day. Why? Because of our naming conventions and the overall cleanness, the code was easy to read. Bad behaviour would pop out like a dirty spot on a white screen, making it easy to pinpoint and fix. Bad code would "sound" out of place. Also, learning how to use GDB and Valgrind proved to be just as great of an asset as my newfound obsession of writing clean code. The result? One of the best managed projects of my life. For the assembler, we continued with the same strategy, and we were just as successful.

Changing the Raspberry Pi Kernel to make an LED blink

No alt text provided for this image

This was the third part of the overall project. A much simpler one, yet fun nonetheless. We have created a new file, which we have written in the ARM11 assembly language. We have found out that, to turn on and of a pin on the Raspberry Pi board, we had to access some virtual memory bits and turn them on. Turning on one of those bits was supposed to turn on the LED and the other was supposed to reset the state of the LED. Our code had to do just that, with some delay in between switches.

To test it, we have assembled the code using our own assembler, then emulated its behaviour using our own emulator. Everything worked fine, until we reinstalled the kernel on the board. For some reason, it would simply not want to boot up.

To solve the issue, we have tested the same code on another Raspberry Pi board, of a different version, which worked fine. The hardware was the issue, we have thought. We then went to a teacher of ours, to ask for a replacement. When sticking the SD card with the kernel on the new board, the same issue occurred. We pinpointed the issue: the SD card was not making proper contact with the board. Changing the card made everything work. Sometimes, issues do happen outside of the box.

The Smart Mirror...

I was extremely proud of our project before building our extension. I have always wanted to make my own Raspberry Pi Smart Mirror, but I don't know why I have not done it before.

Well, now me and the boys have done it, and it looks absolutely beautiful.

No alt text provided for this image

Now, all memes aside, this was not just an extremely fun project. We have learnt a lot from it, including OpenGL, piping and some multi-threading in C.

Now, onto the design. Basically what you see is a completely blank screen, with words and graphics on it. OpenGL basics have only 2-3 font sizes, so that would not work on all screen sizes. So, we had to come up with another way. Cornel, the guy on my left, got the amazing idea to use the vectors in OpenGL to write text. This new text could not just be scaled, but also bolded. It could be as thin or as wide as we would want it to be, or just scaled depending on the size of the display (we could get this information as parameters).

After getting this info out, we inspired ourselves from our previous work and task assignment, and each of us created a different widget for the mirror. We have been responsible to create, in order, from left to right, these widgets: Weather, Calendar, Date & Time and Notes. Everything until this point was made using C.

The calendar, my part, was a bit different. I had to get the calendar information using the Google Calendar API, which, unfortunately, was not made for C. So, I had a script in Python which would take as much relevant information as I wanted from the calendar (the following 10 events, at least). This calendar update script, if it were to run in sequence with the rest of the code, would make the whole mirror stop working for 40 seconds, until the calendar got the data. To mitigate this issue, I would use the pthreads library to run the python script in a separate thread, and get the information whenever it finished updating.

Now, as they say, the rest is history. We finished the code, bought a semi-reflective panel from Amazon, and presented our work with a proud smile on our faces. Now, I have kept the mirror and am actively improving on its capabilities, hoping that some day it would become my household organiser (I have already turned my Raspberry Pi into a Google Assistant).

If you want to use our Smart Mirror code, please clone this repository. The Readme file should get you started on how to set it up on your device. Any criticism is welcomed.

Ending remarks

This whole project went as well as anybody could hope it would. We finished everything on time, scored almost perfect marks and kept the whole thing as an award (especially the Smart Mirror). Was it a perfect project? No, no project is perfect. It can be perfected, though. Rereading what we have written made me think "hmmm, perhaps I could have wrote this better, renamed this, found a more elegant solution for that, make some utilities global between the emulator and the assembler etc.". The great part is that we can always improve our past projects, if we choose to continue to improve ourselves and dare to look on our past mistakes. Most projects, even some of my old hackathon projects, have potential. We are just scared to read old code when it is written in a quick and awkward manner, with no structure.

I am still scared to look on my hackathon projects. I must admit that I would much rather start the project from scratch rather than make out what garbage I have written in 24 hours of speed coding and no sleep. However, when looking at this project, it was much different. Everything made sense, even now, after 4 months of not working on it. I could see places where I could make improvements, but that was again, because I have worked to make it clean in the first place. I am telling you, this project is 10 times as big as any of my hackathon projects, yet it's easier to read than any of them.

Be proud of your work, and keep it beautiful. If you care about it, you will treat with more respect, take time when trying to change it. As the poet Antoine de Saint-Exupery said once, "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away". Think of that when refactoring your next project.

Fast code rots. Clean code stays forever.

Yasin Eden Ibraim

UTCN ETTI graduate & .NET Developer

5 年

OMG you actually did it! :D

要查看或添加评论,请登录

Tiberiu Andrei Georgescu的更多文章

  • How to Win a Hackathon

    How to Win a Hackathon

    Did you ever participate in a hackathon? If you're an engineer, I cannot recommend the experience enough. It's a fun…

    3 条评论
  • True Concurrency: Parallel Picture Processing in C

    True Concurrency: Parallel Picture Processing in C

    Some of my peers find me a little bit of a masochist for this, but I love writing concurrent code. It is so satisfying…

    2 条评论
  • WACC Compiler Project

    WACC Compiler Project

    & Semi-Book Review for "Engineering a Compiler" This year was tough. Next to courses that took a long time to prepare…

    2 条评论
  • First Job: Teaching Game Development

    First Job: Teaching Game Development

    The year before coming to Imperial was one of my more interesting ones. I had my baccalaureate to take, and a lot to…

    1 条评论
  • Chainhack24: My first hackathon, in Blockchain!

    Chainhack24: My first hackathon, in Blockchain!

    I always said that I would talk more about my first hackathon, in London. The event was called Chainhack24, and took…

  • Clean Code - Review

    Clean Code - Review

    I have recently finished reading this masterpiece of a book. I started reading it while working on a group programming…

  • #100DaysOfCode 22/100: Oh boy, here comes Computer Vision

    #100DaysOfCode 22/100: Oh boy, here comes Computer Vision

    Ok, this is the first time I'm using the article thing on LinkedIn, and it's for a DayOfCode! You may think that it's…

社区洞察

其他会员也浏览了