Share your cool programs!

  • litchralee@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    7
    arrow-down
    1
    ·
    edit-2
    2 days ago

    Using an MSP430 microcontroller, I once wrote an assembly routine that (ab)used its SPI peripheral in order to stream a bit pattern from memory out to a GPIO pin, at full CPU clock rate, which would light up a “pixel” – or blacken it – in an analog video signal. This was for a project that superimposed an OSD onto the video feed of a dashcam, so that pertinent vehicle data would be indelibly recorded along with the video. It was for one heck of a university project car.

    To do this, I had to study the MSP430 instruction timings, which revealed that a byte could be loaded from SRAM into the SPI output register, then a counter incremented, then a comparison against a limit value in a tight loop, all within exactly 8 CPU cycles. And the SPI completes an 8-bit transfer every 8 SPI clock cycles, but the CPU and SPI blocks can use the same clock source. In this way, I can prepare a “frame buffer” of bits to write to the screen – plenty of time during the vertical blanking interval of analog video – and then blast it atop the video signal.

    I think I ended up running it at 8 MHz, which gave me sufficient pixel resolution on a 480i analog video signal. Also related was the task of creating a set of typefaces which would be legible on-screen but also be efficient to store in the MSP430’s limited SRAM and EEPROM memories. My job was basically done when someone else was able to use printf() and it actually displayed text over the video.

    This MSP430 did not have a DMA engine, and even if it did, few engines permit an N-to-1 transaction to write directly to the SPI output register. Toggling the GPIO register directly was out of the question, due to taking multiple clock cycles to toggle a single bit and load the next value. Whereas my solution was a sustained 1 bit per clock cycle at 8 MHz. All interrupts disabled too, except for the vertical and horizontal blanking intervals, which basically dictated the “thinking time” available for the CPU.