If you remember the little Network Attached Storage box from the last post, I've had a few issues arise from trying to use it for backups, and now it does something entirely different!
The main issue with using a NAS device on my current home network is our inability to build a wired network in the rental property. In order to keep ethernet cables safe we would need to drill holes in walls, and our management company would probably not react well to that. Because of this the only option for backing up to the NAS is over the network, unless you have an older laptop with an ethernet port! None of us tenants have an ethernet-capable tower right now. A backup over wireless is of course VERY slow, and I don't think anyone is interested in letting their laptop sit for over a day to complete a backup. So instead of letting this machine sit forgotten and unused for backups, I decided I would flash a Linux Mint OS to it and send the desktop output to the TV we keep in the room with this machine and the network router. This machine still has access to the 2TB memory installed in the case, and has just enough processing power to emulate some light handheld video games. So far Game Boy, Game Boy Color, and Game Boy Advance emulation works well up to a certain resolution setting. The Raspberry Pi 4 starts to struggle with emulation framerates at around one quarter of the total resolution of our 48" TV, which I think is 4k, so we might set the boundary around 1080p [which is in fact the official rating for the video output]. I haven't moved enough complex GBA games to this machine yet, so I'm not sure how general computational intensity versus video output scale yet, but this makes a decent Linux PC and Retro Gaming setup for a group setting or party. This machine can also serve as an experimental machine, though virtualization is probably not feasible.
0 Comments
Most of these photos are from a PC tower so I'll cover that first. This PC build is something I advised my dad about after he purchased the case and most of the internal parts. While initially the collection of parts meets the needs of the simulations my dad runs at home, my biggest concern with this setup is the limited air-intake area on the tower case. The general convention when designing a tower setup with desirable air-flow tends to place intake near the lower front face of the case, and exhaust at the upper-back face or rear-top face. However this case has a very narrow intake opening on the front-bottom face. I found this particularly concerning because, especially on a carpeted floor, this can add resistance to the motion of air intake, and cause more dust to catch in this rather acute opening, as opposed to a larger one that faced front and interacted with open air. While I would advise a different case entirely, this PC isn't seeing gratuitous use, so I'm not worried that it'll get clogged with dust any time soon.
The final 2 images in this slideshow are of a light-weight Network Attached Storage server that runs on a RaspberryPi. I have built 2 of these now, one at my parents' house in Wisconsin, one at my house in Brighton MA. Getting the device set up in WI was slow and difficult because the internet connection was slow and not entirely reliable. I had to repeatedly attempt updating PiOS and installing Open Media Vault through failed or timed-out connections, until I found that the network had inadvertently assigned the Pi the wrong IP address. After resolving this, things went pretty smoothly. Setting up a similar device in Boston went very quickly because we have about a 0.5Gb uplink from the ISP, but the hardware assembly was a little different. In both cases we encounter one critical issue, and that is the limit of data transfer over Wi-Fi Networks. While these NasPi devices were originally intended for storing backup images, the usual bandwidth of a wireless network can cause a backup to take 12 or more hours to complete. This is not ideal if you are backing up a computer with limited RAM, as you might be inclined not to use it during backup operations. If I had greater control over the network infrastructure at both locations, I would like to ensure that both the storage device, and the PC being backed up were connected to the network by an ethernet connection, so that the only limitations on the backup operation are internal to the involved devices. There are still a few things I needed to clear up for myself after the JTAG standard:
What does Board Bring-Up entail as a phase of development?: From Asset InterTech - Board bring-up is a phased process whereby an electronics system, inclusive of assembly, hardware, firmware, and software elements, is successively tested, validated and debugged, iteratively, in order to achieve readiness for manufacture. What is an Exception or Interrupt Vector Table?: This is a data structure that associates interrupt-handling routines with a group of interrupt-requests in a table of interrupt vectors. Each entry in the table is the address of an interrupt-handling routine. This is structure is common throughout processor architectures, but it can also be implemented in different architecture-specific fashions. What does the Stack do again?: In computer science, computer engineering and programming language implementations, a stack machine is a computer processor or a virtual machine in which the primary interaction is moving short-lived temporary values to and from a push down stack. In the case of a hardware processor, a hardware stack is used. The use of a stack significantly reduces the required number of processor registers. Stack machines extend push-down automata with additional load/store operations or multiple stacks and hence are Turing-complete. Over the evolution of the computer and emergence of virtual stack machines there have been a wide array of implementations. A somewhat recent example relevant to the study of embedded systems is the ZPU microprocessor stack machine. It was designed Zylin AS to run supervisory code for FGPA systems. What is Turing-Completeness?: In computability theory, a system of data-manipulation rules (such as a model of computation, a computer's instruction set, a programming language, or a cellular automaton) is said to be Turing-complete or computationally universal if it can be used to simulate any Turing machine (devised by English mathematician and computer scientist Alan Turing). This means that this system is able to recognize or decide other data-manipulation rule sets. Turing completeness is used as a way to express the power of such a data-manipulation rule set. Virtually all programming languages today are Turing-complete. What do we mean in Computer Science when we say Implicit or Explicit?: Something that is implicit is done for you behind-the-scenes, whereas something explicit is the manual approach to achieving a change we want by writing out the instructions to be done. And finally, What is Clock Stabilization?: Let's take the example of crystal oscillator used for clock timing, and an accompanying Oscillator Startup Timer (OST). When a crystal oscillator starts up, the frequency of its pulse is not constant, and would cause the clock pulse to also be non-constant. This would lead to timing errors, which would propagate into a slew of other problems. The OST ensures that the system only operates when the oscillator produces a stable pulse. It generally holds the system's reset for a set number of oscillator cycles to wait for a stable pulse. Making Embedded Systems is published by O'Reilly Media Inc. and is written by Elecia White. Elecia White is the founder of Logical Elegance, and embedded systems consulting company in San Jose, California. O'Reilly publishes books for education, business, and sales promotion, and the cover art of a great-eared nightjar is an original work by their illustrator Robert Romano.
Intro & Preface Material: The preface discusses the use of Design Patterns in 'pure' software engineering, and that these patterns cannot necessarily apply to embedded systems due to its mechanics. These include compilers that do not handle C++ inheritance, and processors with very small amounts of memory, so restrictive that some patterns simply do not work. About the book: The main goal is to discuss good software design in resource-constrained environments. It also provides advice for applying to embedded systems jobs and interviews. However these embedded systems also work without operating systems, so that there is no intermediary between code and machine. The concepts do transfer to processors that run OSs, and the book eventually works with the low-level end of operating systems. Specific platforms and languages are not covered in this book because the author's goal is to establish a working foundation that can handle specifics later. Beginning terminology for this book: Microcontroller: A Processor with on-board peripherals like RAM, code-space, and I/O CPU - Central Processing Unit: Executes code Microprocessor: A 'small' processor where the definition of 'small' is a bit elastic. DSP - Digital Signal Processor: A specialized microcontroller designed for signal processing, usually samples analog signals and performs a task with the result. DSPs also typically have tweaks that accelerate certain math operations, namely add and multiply. Throughout the book the author refers to a 'processor' as whatever is being used to implement code. The words 'embedded system' might conjure very different imagery for different people. To an engineer working on servers, an application developed to run on a smartphone is an embedded system. But for one who has written code for 8-bit processors, anything with an operating system doesn't seem embedded. Embedded systems often appear in devices like microwaves or cars which run software but are not computers. Most simply put - An embedded system is a computerized system that is purpose-built for its application. Because the goal of functionality of narrower than that of a general-purpose computer, an embedded system has less support for things unrelated to the chosen task. Hardware often has constraints, like a slower CPU that conserves battery power, small memory stores for cheaper manufacturing, and processors with limits on speed and peripheral connections. In some systems software must act deterministically - the same every time - or in real-time - always responding to events fast enough. Some systems call for software that is fault-tolerant, because maintenance may be infeasible. Others must cease operation and make an alert at the first sign of trouble. A heart monitor should not fail quietly. Embedded systems can also be identified by the use of cross-compilers. Though the compiler runs on a desktop, the compiled code cannot. The compiled image runs on the target system. Vendors for target systems typically sell or provide access to a cross-compiler that is compatible with their product. These compilers often only support C, or C and C++. Many C++ compilers also only implement a subset of the language functionality, leaving out multiple inheritance, exceptions, and templates. Java's popularity is growing, though its memory management can only work in larger systems. Regardless of the language, we can practice Object Oriented Design. Encapsulation, Modularity, and Data Abstraction can be applied to any application in almost any language. We want a design that is Robust, Maintainable, and Flexible. An embedded system CAN be regarded as an Object, one that works in a larger system. At the higher levels of software engineering everything can be Object-Oriented, and this can extend down to embedded software. However, not all principles of OOD should be followed strictly when designing embedded systems. Once the tradeoffs are understood, the goals of software design and system design should be balanced. Embedded System Development: Most engineers develop a toolkit for working with constraints. Before starting to build an embedded system, we should establish the difficulties associated with the task. Principles based on the known limitations of the system are used to reach better solutions. Debugging: When debugging software that runs on a computer, you can compile, run, and debug on the same device, and the run and debug procedures can be done simultaneously with the available resources. This generally cannot happen with embedded systems. Developers need both a cross compiler and a cross-debugger. This type of debugger runs on a computer but communicates with a target processor through a specialized interface. The interface generally allows one to examine the processor as it works, and is often called JTAG, regardless of whether it implements that standard. A processor must use some of its resources to support debugging procedures, which includes halting and stepping through code. The support adds to the general cost of a processor however, and some processors offer limited debugging functions. A processor can add a break-point to memory-loaded code, but if that code is executing from a read-only memory source, the processor must set an internal register as a break-point, and compare it at each execution cycle to address being run, stopping, and when they match. This can change the timing of the code, causing bugs that may only occur when debugging! This leads to a limit on the use of internal registers as breakpoints, usually only 2. The device that communicates between a PC and processor is called an Emulator, In-Circuit-Emulator, or a JTAG adapter. Emulators are specific to a processor or processor family, so they often do not translate between projects. Emulator costs can add up in large numbers or if a large team works on a project. To avoid the cost of emulators or dealing with processor limitations, many embedded systems are designed to debug via printf or some lightweight logging on an otherwise unused communication port. Though this can be useful, it can change the timing of the system, and some bugs may only appear when this debugging is disabled. Our software must also be debuggable in a somewhat hostile environment. More Challenges: An embedded system performs a specific task, and casts out resources that are not necessary. These include Memory(RAM), Code Space(ROM/flash), Processor Speed/Cycles, Power Consumption, and Peripherals. These resources are interchangeable to an extent, as they are interrelated. Code Space can be traded for processor cycles, processor speed can be lowered to conserve power, and peripheral interfaces can be made in software. Resource constraints present one of the most pressing challenges of embedded systems. Challenges also come from working with the hardware. Sometimes it may be unclear whether a bug is occurring in software or hardware, and the software could easily cause damage to hardware. Most important here is that we understand the hardware and its capabilities. The designed system must be manufacturable at a reasonable cost, and both software and hardware engineers must pursue this. After manufacture, products go into the field. With consumer products, they go into millions of homes where bugs can be enjoyed by many! In the medical, aviation, and other critical fields, bugs may be catastrophic. This is why we do paperwork for our QA reps. In science and monitoring the product may never be retrieved, so it better work. We must be mindful of the full lifecycle of the product when we design our software. Product goals and project needs can and do change. The form of the project will not be the same between the start and end of development, and development rarely fully ends. Creating a system that is purpose built for an application has an unfortunate caveat: the system may not support change as the application changes. We cannot only worry about the known constraints, but must extrapolate which constraints could become problems later. We must anticipate changes and design flexible software that can accommodate change. Principles to Confront Challenges: Abandon the notion that the final product is a single version of code shipped at the end of a project. Approach projects in phases: Conception, Prototyping, Board Bring-Up, Debugging, Testing, Release, Maintenance, Repeat. Flexibility includes not just the capabilities of the code, but how it will handle its lifespan. The goal is to be flexible enough to meet product goals while dealing with the constraints inherent to embedded systems. Modularity should be used to separate functionality into subsystems and hide the data each subsystem uses. Encapsulation should be used to create Interfaces between subsystems, so they don't know much about each other. When we have loosely coupled subsystems we can modify one area with the confidence that it will not affect another. Where do we break up a system? What parts can change independently? These questions can also find some help from the presence of physical objects. If a sensor A communicates on a channel B those are separate things and good candidates for being put in separate code modules. "Bugs caught before software releases are like gifts" The earlier bug is caught, the cheaper and better the fix. Writing test code for a system makes it better, provides documentation, and makes it look like you write great code. Documenting code also reduces bugs. Write comments for someone who will read the code in a year. You may not even remember writing the code, but function and file headers about what the code does helps orient others in the future. Implement features, test them, make them work, THEN optimize code. There is limited time. Focus on big resource consumers after a subsystem is working. Dealing with constraints REQUIRES some optimization, but that optimization must have a clear intent and effects. "Premature optimization is the root of all evil" Interview Question: "Here is a computer with a compiler and an editor. Please implement 'Hello World'. Once you have the basic version working, add in the functionality to get a name from command line. Finally, tell me what happens before your code executes - before the main() function." In many embedded systems, we develop from scratch. Candidates need to take a blank slate and fill in the basic functionality, even in an unfamiliar environment. Any language on a resume is fair game, and specifics of the language will be examined. Find and fix syntax errors. Before main() 'start' or 'cstart' should begin your discussion. These occur before the code we see in the editor, no matter the platform. It's good to mention the setting of exception vectors to handle interrupts, initializing peripherals, initializing the stack, initializing variables, and if there are C++ objects, calling the creators for those. What happens implicitly - in the compiler - and explicitly - in initialization code. The best answers are step-by-step descriptions of what might happen, an explanation of why they are important and how they happen in an embedded system. An experienced engineer often starts at the vector table, with reset vector, then moves to power-on behavior. An electrical engineer gives bonus points when a candidate can explain why a system cannot be up and running 1 microsecond after the power is switched on. EE looks for understanding of power-sequencing, power ramp-up time, clock stabilization, and processor reset/initialization delay. What is the JTAG standard?: JTAG, named after the Joint Test Action Group which codified it, is an industry standard for verifying designs and testing printed circuit boards after manufacture. It specifies the use of a dedicated debug port implementing a serial communications interface for low-overhead access without requiring direct external access to the system address and data buses. The interface connects to an on-chip Test Access Port (TAP) that implements a stateful protocol to access a set of test registers that present chip logic levels and device capabilities of various parts. More here |
Caylan Laundrie
Caylan is an IT Technician and Musican, planning to specialize in Computing Security and maintain a vibrant performing and teaching career. Archives
October 2024
Categories |