Add more comments

This commit is contained in:
schmelczerandras 2020-04-19 20:55:44 +02:00
parent 26e48fd997
commit b5a95218ea
25 changed files with 200 additions and 60 deletions

View file

@ -22,7 +22,7 @@
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<UncachedRange />
<preserveEEPROM>true</preserveEEPROM>
<preserveEEPROM>false</preserveEEPROM>
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<ResetRule>0</ResetRule>

View file

@ -43,6 +43,7 @@ void turnDisplayOnOff(bool shouldBeOn) {
sendByteOnSPI(0x8D | shouldBeOn); // set charge pump on/off
sendByteOnSPI(0x10 | shouldBeOn << 2); // set charge pump on/off
sendByteOnSPI(0xAE | shouldBeOn); // turn display sleep on/off
dataMode();
}
void initializeDisplay(DrawFunction drawEverything) {

View file

@ -7,30 +7,65 @@
#include "../../util/rectangle/rectangle.h"
/*
SPI driver for D096-12864
*/
#define DISPLAY_RESET_OUTPUT_PIN PB0
#define DISPLAY_DC_OUTPUT_PIN PB4
// A two-times downscaling is used for greater performance
#define DISPLAY_WIDTH_IN_PIXELS 64
#define DISPLAY_HEIGHT_IN_PIXELS 32
// To easily access the window size
#define WINDOW ((Rectangle){(Vec2){0, 0}, (Vec2){DISPLAY_WIDTH_IN_PIXELS, DISPLAY_HEIGHT_IN_PIXELS}})
// To conserve RAM, drawing is done in chunks of DEFAULT_COMPOSITING_WINDOW size
// instead of buffering the whole display and writing it out at once
#define DEFAULT_COMPOSITING_WINDOW ((Rectangle){(Vec2){0, 0}, (Vec2){DISPLAY_WIDTH_IN_PIXELS, 8}})
typedef void (*DrawFunction)(Rectangle);
// Call DrawFunction n times after a call to drawFrame has been made
void initializeDisplay(DrawFunction drawEverything);
// Set a the brightness of the display
// Value can be any number between 0 and 255.
void setDisplayContrast(uint8_t value);
void turnDisplayOnOff(bool shouldBeOn);
// To conserve program memory, pixel based intersection test
// is implemented here.
// Calling draw functions after calling startIntersectionTest
// will set a wasIntersection bit appropriately.
// Clear buffer and wasIntersection bit
void startIntersectionTest();
// Return wasIntersection bit
bool endIntersectionTest();
// Initiate a draw sequence
void drawFrame();
void drawBitmapFromProgMem(Rectangle boundingBox, uint16_t const data[boundingBox.size.x][(boundingBox.size.y + 7) / 8], bool isMirrored);
// for white rectangle: invertedMask: don't care, fill: 0xFF
// for black rectangle: invertedMask: 0xFF, fill: 0x00
// Draw a sprite of size boundingBox.size at boundingBox.position from bitmap
// if isMirrored then mirror around the vertical axis
// Bitmap's data is interpreted the following way:
/*
Each 16 bit word corresponds to an 8 pixel high column.
(These columns are laid out horizontally from left to right. Unfortunately,
the display uses this addressing mode.) The higher 8 bits of the word is the
an inverted mask and the lower 8 bits are the fill bits.
newPixelColumn = oldPixelColumn & ~invertedMask | fill;
This seemingly weird layout is used to take advantage of SIMD operations
and speed up the drawing process significantly.
*/
void drawBitmapFromProgMem(Rectangle boundingBox, uint16_t const bitmap[boundingBox.size.x][(boundingBox.size.y + 7) / 8], bool isMirrored);
// Draw a one byte repeated texture covering the parameter box
// for a white rectangle use these arguments: invertedMask: don't care, fill: 0xFF
// for a black rectangle use these arguments: invertedMask: 0xFF, fill: 0x00
void drawFilledRectangle(Rectangle box, uint8_t invertedMask, uint8_t fill);
#endif

View file

@ -5,13 +5,19 @@
#include <avr/io.h>
/*
Custom NEC implementation using a TSOP4838
*/
#define INFRA_ADDRESS 255
#define IR_PIN PB3
#define IR_PIN PB4
#define REPEAT_CODE 1
typedef void (*OnCommandReceived)(uint8_t);
typedef void (*OnReceiveStarted)();
void initializeInfra(OnCommandReceived onCommandReceived, OnReceiveStarted onReceiveStarted);
// Initialize infra and call onCommandReceived with every received byte
// Call onCommandReceived with the argument REPEAT_CODE if a repeat code
// has been received.
void initializeInfra(OnCommandReceived onCommandReceived);
#endif

View file

@ -4,12 +4,10 @@
#include <stdbool.h>
#include <avr/io.h>
// FrameFunction gets previousFrameTime (in milliseconds) as argument
typedef bool (*FrameFunction)(uint8_t);
// frameFunction gets previousFrameTime (in milliseconds) as argument
// Call function every frameLengthInMilliseconds while it returns true
void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds);
void powerOff();
#endif

View file

@ -12,22 +12,49 @@
#include "output_pins/output_pins.h"
/*
This module contains the lowest level functions to manipulate the hardware.
You only have to include this header file which serves as a facade.
The sub-modules' implementation can be freely changed as long as they
still implement these functions.
*/
// Initialize every hardware element at once
void initializeHardwareAccess();
// writing of unchanged byte is atomic
// Write a single byte, when finished call the callback method
// Writing of unchanged byte is atomic.
bool asyncWriteEEPROM(uint8_t* buffer, OnEEPROMFinished onFinished);
uint8_t loadSavedByteEEPROM(uint8_t address);
// Load byte from pointer
uint8_t loadByteEEPROM(uint8_t* address);
// Load 2 bytes from pointer
uint16_t loadWordEEPROM(uint16_t const* address);
// Load byte from address
// It is different from loadByteEEPROM because
// accepts a relative address instead of an
// absolute one.
uint8_t loadSavedByteEEPROM(uint8_t address);
// Enable the asynchronous writing of data from buffer
void enableWritingEEPROM();
void disableWritingEEPROM();
// Enable interrupt OCCRA for TIMER0 with a modulo of triggerInterruptInXTicks
void enableTimerA(uint8_t triggerInterruptInXTicks);
// Enable interrupt OCCRB for TIMER0B with a modulo of triggerInterruptInXTicks
void enableTimerB(uint8_t triggerInterruptInXTicks);
void disableTimerB();
// Send a single byte on the built-in SPI interface
// The transfer is done in a serial manner to achieve
// greater throughput.
void sendByteOnSPI(uint8_t byte);
// Set the value of an output pin
void setOutputPin(uint8_t id, bool value);
#endif

View file

@ -7,7 +7,7 @@
inline void initializePowerSaving() {
setBit(ACSR, ACD); // disable ADC to save power
PRR = BV(PRTIM1) | BV(PRADC); // disable power of timer1 and ADC
PRR = BV(PRTIM1) | BV(PRADC); // disable power to timer1 and ADC
}
#endif

View file

@ -12,6 +12,4 @@ inline void initializeSPI() {
DDRB |= BV(DO_PIN) | BV(USCK_PIN); // set pin directions for MOSI and SCK
}
void sendByteOnSPI(uint8_t byte);
#endif

View file

@ -4,9 +4,20 @@
#include <avr/io.h>
// Setup the drivers, and business layer objects and their relations
// It is kind of a very basic dependency injection.
void setupConnections();
// Start drawing frames and ticking objects
void startGame();
// Make the machine go to sleep
void handleOff();
// Increase or decrease the contrast (brightness) of the display
// by the given value
// The contrast can be any number between 0 and 255.
// The function automatically clamps the contrast.
void changeDisplayContrast(int8_t by);
#endif

View file

@ -46,7 +46,7 @@ bool generateAstronautPredicate(Rectangle* proposedBoundingBox) {
return (
(
(getCountOf(&Astronaut) == 1 && spaceshipObject->as.spaceship.progress >= hasHalfCrew) ||
(getCountOf(&Astronaut) == 2 && spaceshipObject->as.spaceship.progress >= hasFullCrew)
(getCountOf(&Astronaut) == 2 && spaceshipObject->as.spaceship.progress >= hasTable)
) &&
getIntersectingObjectOfType(*proposedBoundingBox, &Astronaut) == NULL &&
isOnboard(*proposedBoundingBox)

View file

@ -46,8 +46,7 @@ typedef enum {
hasBeds = 2,
hasTurret = 5,
hasHalfCrew = 8,
hasFullCrew = 15,
hasTable = 25,
hasTable = 15
} Progress;
struct _spaceship_t {

View file

@ -228,9 +228,6 @@
<Compile Include="src\driver\uart\transmit.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\hardware_access\eeprom\eeprom.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\hardware_access\hardware_access.c">
<SubType>compile</SubType>
</Compile>
@ -387,7 +384,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="src" />
<Folder Include="src\controller\" />
<Folder Include="src\driver\" />
<Folder Include="src\driver\display\" />
<Folder Include="src\driver\infra\" />

View file

@ -7,29 +7,65 @@
#include "../../util/rectangle/rectangle.h"
/*
SPI driver for D096-12864
*/
#define DISPLAY_RESET_OUTPUT_PIN PB0
#define DISPLAY_DC_OUTPUT_PIN PB4
// A two-times downscaling is used for greater performance
#define DISPLAY_WIDTH_IN_PIXELS 64
#define DISPLAY_HEIGHT_IN_PIXELS 32
// To easily access the window size
#define WINDOW ((Rectangle){(Vec2){0, 0}, (Vec2){DISPLAY_WIDTH_IN_PIXELS, DISPLAY_HEIGHT_IN_PIXELS}})
// To conserve RAM, drawing is done in chunks of DEFAULT_COMPOSITING_WINDOW size
// instead of buffering the whole display and writing it out at once
#define DEFAULT_COMPOSITING_WINDOW ((Rectangle){(Vec2){0, 0}, (Vec2){DISPLAY_WIDTH_IN_PIXELS, 8}})
typedef void (*DrawFunction)(Rectangle);
// Call DrawFunction n times after a call to drawFrame has been made
void initializeDisplay(DrawFunction drawEverything);
// Set a the brightness of the display
// Value can be any number between 0 and 255.
void setDisplayContrast(uint8_t value);
// To conserve program memory, pixel based intersection test
// is implemented here.
// Calling draw functions after calling startIntersectionTest
// will set a wasIntersection bit appropriately.
// Clear buffer and wasIntersection bit
void startIntersectionTest();
// Return wasIntersection bit
bool endIntersectionTest();
// Initiate a draw sequence
void drawFrame();
// Draw a sprite of size boundingBox.size at boundingBox.position from bitmap
// if isMirrored then mirror around the vertical axis
// Bitmap's data is interpreted the following way:
/*
Each 16 bit word corresponds to an 8 pixel high column.
(These columns are laid out horizontally from left to right. Unfortunately,
the display uses this addressing mode.) The higher 8 bits of the word is the
an inverted mask and the lower 8 bits are the fill bits.
newPixelColumn = oldPixelColumn & ~invertedMask | fill;
This seemingly weird layout is used to take advantage of SIMD operations
and speed up the drawing process significantly.
*/
void drawBitmapFromProgMem(Rectangle boundingBox, uint16_t const bitmap[boundingBox.size.x][(boundingBox.size.y + 7) / 8], bool isMirrored);
// for white rectangle: invertedMask: don't care, fill: 0xFF
// for black rectangle: invertedMask: 0xFF, fill: 0x00
// Draw a one byte repeated texture covering the parameter box
// for a white rectangle use these arguments: invertedMask: don't care, fill: 0xFF
// for a black rectangle use these arguments: invertedMask: 0xFF, fill: 0x00
void drawFilledRectangle(Rectangle box, uint8_t invertedMask, uint8_t fill);
#endif

View file

@ -6,7 +6,6 @@
#include "bitwise.h"
#include "../../hardware_access/hardware_access.h"
#include "../uart/receive.h"
#include "../uart/transmit.h"
// (0.5625 + (0.5625 + 1.6875) / 2) / 1000 / timer interval
@ -49,7 +48,6 @@ static void saveCurrentByte() {
break;
case significantByte:
infra.onCommandReceived(byte);
sendUintOnUartAsync(byte);
infra.commandState = waitingForEndOfCommand;
break;
case waitingForEndOfCommand:

View file

@ -5,12 +5,19 @@
#include <avr/io.h>
/*
Custom NEC implementation using a TSOP4838
*/
#define INFRA_ADDRESS 255
#define IR_PIN PB4
#define REPEAT_CODE 1
typedef void (*OnCommandReceived)(uint8_t);
// Initialize infra and call onCommandReceived with every received byte
// Call onCommandReceived with the argument REPEAT_CODE if a repeat code
// has been received.
void initializeInfra(OnCommandReceived onCommandReceived);
#endif

View file

@ -20,7 +20,6 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) {
previousFrameTime = milisecondsSinceFrameStart;
while (milisecondsSinceFrameStart < frameLengthInMilliseconds) {
clearBit(MCUCR, SM1); // idle mode
sleep_cpu();
}
@ -28,10 +27,6 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) {
}
}
void powerOff() {
setBit(MCUCR, SM1); // power-down mode
sleep_cpu();
}
ISR(TIM0_COMPA_vect) {
milisecondsSinceFrameStart++;

View file

@ -4,10 +4,10 @@
#include <stdbool.h>
#include <avr/io.h>
// FrameFunction gets previousFrameTime (in milliseconds) as argument
typedef bool (*FrameFunction)(uint8_t);
// frameFunction gets previousFrameTime (in milliseconds) as argument
// Call function every frameLengthInMilliseconds while it returns true
void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds);
#endif

View file

@ -1,15 +1,24 @@
#ifndef RECEIVE_H
#define RECEIVE_H
// 8*10^6 / 256 / 1200
/*
Custom UART receive implementation with a baud rate of 2400
*/
// 8*10^6 / 128 / 2400
#define BIT_TIME 26
#define RECEIVE_PIN PB3
typedef void (*OnCommandReceived)(uint8_t);
// Initialize UART and call onCommandReceived with every byte received
void initializeUartReceive(OnCommandReceived onCommandReceived);
// Check for change on the UART receive pin
// This function exist so we can use a single interrupt
// handler for both the UART receive and infra pins.
// Unfortunately, it's not possible to use more than one handler.
void handlePinChangeForUartReceive();
#endif

View file

@ -4,15 +4,30 @@
#include <avr/io.h>
// 8*10^6 / 256 / 1200
/*
Custom UART trasnmit implementation with a baud rate of 2400
*/
// 8*10^6 / 128 / 2400
#define BIT_TIME 26
// Messages cannot be longer than this many characters (including trailing zero)
#define ASYNC_BUFFER_SIZE 20
#define UART_OUTPUT_PIN 2
// Start pulling-up the transmit line
void initializeUartTransmit();
// Send a single byte over on UART
// It's done in an asynchronous fashion using a circular buffer.
void sendByteOnUartAsync(char byte);
// Send a string over on UART
// It's done in an asynchronous fashion using a circular buffer.
void sendTextOnUartAsync(char text[]);
// Send the decimal form of unsigned integer over UART
void sendUintOnUartAsync(uint8_t number);
#endif

View file

@ -1,15 +0,0 @@
#ifndef EEPROM_H
#define EEPROM_H
#include <avr/io.h>
#define STORAGE_SIZE 52
typedef void (*OnEEPROMFinished)(uint8_t*);
inline void initializeEEPROM() {
EECR = 0; // atomic write
}
#endif

View file

@ -7,24 +7,45 @@
#include "power_saving/power_saving.h"
#include "spi/spi.h"
#include "eeprom/eeprom.h"
#include "timing/timing.h"
#include "output_pins/output_pins.h"
/*
This module contains the lowest level functions to manipulate the hardware.
You only have to include this header file which serves as a facade.
The sub-modules' implementation can be freely changed as long as they
still implement these functions.
*/
// Initialize every hardware element at once
void initializeHardwareAccess();
// Enable interrupt OCCRA for TIMER0 with a modulo of triggerInterruptInXTicks
void enableTimerA(uint8_t triggerInterruptInXTicks);
// Enable interrupt OCCRB for TIMER0B with a modulo of triggerInterruptInXTicks
void enableTimerB(uint8_t triggerInterruptInXTicks);
void disableTimerB();
// Enable interrupt OCCRA for TIMER1 with a modulo of triggerInterruptInXTicks
void enableFastTimerA(uint8_t triggerInterruptInXTicks);
void disableFastTimerA();
// Return TCNT1
uint8_t getTimestampFromFastTimer();
// Return the time since a timestamp returned by getTimestampFromFastTimer
// Accounts for overflow.
uint8_t getTimeSince(uint8_t timestamp);
// Send a single byte on the built-in SPI interface
// The transfer is done in a serial manner to achieve
// greater throughput.
void sendByteOnSPI(uint8_t byte);
// Set the value of an output pin
void setOutputPin(uint8_t id, bool value);
#endif

View file

@ -7,6 +7,7 @@
#define CLK_ST_PIN PB0
// Uses a 74HC595 to extend the number of digital outputs
void sendCurrentValue();
inline void initializeOutputPins() {

View file

@ -6,8 +6,8 @@
inline void initializePowerSaving() {
setBit(ACSR, ACD); // disable ADC to save power
PRR = /*BV(PRTIM1) |*/ BV(PRADC); // disable power of timer1 and ADC
setBit(ACSR, ACD); // disable ADC to save power
PRR = BV(PRADC); // disable power to ADC (again?)
}
#endif

View file

@ -12,6 +12,8 @@ inline void initializeSPI() {
DDRB |= BV(DO_PIN) | BV(USCK_PIN); // set pin directions for MOSI and SCK
}
// This function can be used from other sibling sub-modules
// it's required for the current outpu_pins implementation.
void sendByteOnSPI(uint8_t byte);
#endif

View file

@ -6,7 +6,7 @@
inline void initializeTiming() {
TCCR0B = BV(CS02); // CLK / 256
TCCR1 = BV(CS13); // CLK / 128
TCCR1 = BV(CS13); // CLK / 128
TIMSK = BV(OCIE0A) | BV(OCIE1A); // enable compare interrupts
}