From 4dfad70e9b966563157732323d2a44319b77520a Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Mon, 12 Dec 2022 13:31:21 +0100 Subject: [PATCH] Added spi basic control. --- build.d | 45 ++++++++++++++++++++++++++++++++++++++++----- src/spi.c | 32 ++++++++++++++++++++++++++++++++ src/spi.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/spi.c create mode 100644 src/spi.h diff --git a/build.d b/build.d index 8bc6690..7826bed 100755 --- a/build.d +++ b/build.d @@ -9,6 +9,8 @@ import std.file; import std.string; import std.conv; import std.path; +import std.digest.md; +import std.base64; const string MCU_ID = "atmega328p"; const ulong CPU_FREQ = 16_000_000; @@ -28,7 +30,11 @@ int main(string[] args) { return build(); } string command = args[1].strip.toLower; - if (command == "build") return build(); + if (command == "flash") { + build().quitIfNonZero(); + return flashToMCU(buildPath("bin", "gympal.hex")); + } + if (command == "build") return build(true); if (command == "clean") return clean(); writefln!"Unknown command: \"%s\"."(command); @@ -40,18 +46,18 @@ int clean() { return 0; } -int build() { +int build(bool force = false) { if (!exists(BUILD_DIR)) mkdir(BUILD_DIR); string[] sources = findFiles(SOURCE_DIR, ".c"); - writefln!"Found %d source files."(sources.length); string[] objects; objects.reserve(sources.length); foreach (source; sources) { - objects ~= compileSourceToObject(source); + objects ~= compileSourceToObject(source, force); } string elfFile = linkObjects(objects); string hexFile = copyToHex(elfFile); writefln!"Built %s"(hexFile); + runOrQuit("avr-size " ~ hexFile); return 0; } @@ -70,11 +76,34 @@ void runOrQuit(string shellCommand, int[] successExitCodes = [0]) { if (!canFind(successExitCodes, result)) exit(result); } -string compileSourceToObject(string sourcePath) { +void quitIfNonZero(int n) { + import core.stdc.stdlib : exit; + if (n != 0) exit(n); +} + +bool shouldCompileSource(string sourcePath) { + string name = baseName(sourcePath); + name = name[0 .. name.lastIndexOf('.')]; + string hashPath = buildPath("bin", "hash", name ~ ".md5"); + string objectPath = buildPath("bin", name ~ ".o"); + if (!exists(hashPath) || !exists(objectPath)) return true; + ubyte[] storedHash = Base64.decode(readText(hashPath).strip()); + ubyte[16] currentHash = md5Of(readText(sourcePath)); + return storedHash != currentHash; +} + +string compileSourceToObject(string sourcePath, bool force = false) { string flags = join(COMPILER_FLAGS, " "); string name = baseName(sourcePath); name = name[0 .. name.lastIndexOf('.')]; string objectPath = buildPath("bin", name ~ ".o"); + string hashPath = buildPath("bin", "hash", name ~ ".md5"); + + if (!force && !shouldCompileSource(sourcePath)) { + writefln!"Not compiling %s because no changes detected."(sourcePath); + return objectPath; + } + string cmd = format!"avr-gcc %s -DF_CPU=%dUL -mmcu=%s -c -o %s %s"( flags, CPU_FREQ, @@ -84,6 +113,12 @@ string compileSourceToObject(string sourcePath) { ); writeln(cmd); runOrQuit(cmd); + + ubyte[16] hash = md5Of(readText(sourcePath)); + string hashDir = buildPath("bin", "hash"); + if (!exists(hashDir)) mkdir(hashDir); + std.file.write(hashPath, Base64.encode(hash)); + return objectPath; } diff --git a/src/spi.c b/src/spi.c new file mode 100644 index 0000000..bd2602d --- /dev/null +++ b/src/spi.c @@ -0,0 +1,32 @@ +#include "spi.h" + +void spi_initMaster() { + SPI_DDR = ( + (1 << SPI_MOSI) | + (1 << SPI_SCK) + ); + SPCR = ( + (1 << SPE) | + (1 << MSTR) | + (1 << SPR0) + ); +} + +void spi_initSlave() { + SPI_DDR = (1 << SPI_MISO); + SPCR = (1 << SPE); +} + +void spi_masterTransmit(uint8_t data) { + SPDR = data; + while (!(SPSR & (1 << SPIF))) { + // Loop until we confirm transmission is done. + } +} + +uint8_t spi_slaveReceive() { + while (!(SPSR & (1 << SPIF))) { + // Loop until SPI status is done. + } + return SPDR; +} \ No newline at end of file diff --git a/src/spi.h b/src/spi.h new file mode 100644 index 0000000..e069b34 --- /dev/null +++ b/src/spi.h @@ -0,0 +1,33 @@ +#ifndef SPI_H +#define SPI_H + +#include + +#define SPI_DDR DDRB +#define SPI_SCK DDB5 +#define SPI_MISO DDB4 +#define SPI_MOSI DDB3 + +/** + * @brief Initializes this device as an SPI master. + */ +void spi_initMaster(); + +/** + * @brief Initializes this device as an SPI slave. + */ +void spi_initSlave(); + +/** + * @brief Transmits a single byte of data to the currently selected slave + * device. Blocks until transmission is complete. + */ +void spi_masterTransmit(uint8_t data); + +/** + * @brief Receives a single byte of data from a connected master. Blocks + * until the receive is complete. + */ +uint8_t spi_slaveReceive(); + +#endif \ No newline at end of file