Close

Pong in C (part 1)

A project log for AVR Asm Exam

Doing the "exam" of the AVR assembly course

Michael MöllerMichael Möller 02/26/2021 at 19:400 Comments

Display something (with SPI library)

V0.1 is just to do the bare minimum in C to just light a few dots on the display. That was easy and took only "a few minutes". 

/*

  PONG in C
  V0.1 - just display something
  
*/
#include <SPI.h> // H/W uses pin 13, 12, 11, pin 11 is MOSI output

void setup() {
  SPI.begin ();
  pinMode(10,OUTPUT);
  //SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE3));  // MOSI normally low.
}

void loop() {
  digitalWrite(10,LOW);
  SPI.transfer(0x05);
  SPI.transfer(0xAA);
  digitalWrite(10,HIGH);
  delay(5555) ;
  digitalWrite(10,LOW);
  SPI.transfer(0x03);
  SPI.transfer(~0xAA);
  digitalWrite(10,HIGH);
  delay(5555) ;
}

Yes, all hardcoded values. 

Display something (with port access)

The second pre-test version was to avoid using the SPI library.

This required peeking in the SPI library and (sorry) cut-n-paste the initialisation code. I tried to match this with the AVR manual description of the bits in the SPI control register. If the AVR manual was the only information source I probably would not have managed, possibly simply brute force trying all combinations until it worked.

The same with the send-one-byte routine.

This only took "half  an hour".

// (Cant find where they are defined, so doing it myself
// SPI pins are hardwired to 13, 12 & 11
#define PORT_SPI    PORTB   // The SPI port is part of Port B
#define DDR_SPI     DDRB    // -"-"
#define DD_MISO     DDB4    // Port number for pin 11
#define DD_MOSI     DDB3    // (not using this - pin 12)
#define DD_SCK      DDB5    // Port number for pin 13

byte CSS = 10 ;  // the ChipSelect pin

void SPIout ( byte Bits ) {
  // Output a byte to SPI - block until complete
  SPDR = Bits ;
  while(!(SPSR & (1<<SPIF)) ) ; // Wait until complete
}

void setup() {
  // to be nicer it should mask the other pins, ie not change them
  DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK); // Set MOSI and SCK output, all others input
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); // Enable SPI, Controller, set clock rate fck/16
  pinMode(10,OUTPUT); // Ready the chip select
}

void loop() {
digitalWrite(10,LOW);
  SPIout(0x05);
  SPIout(0xAA);
  digitalWrite(10,HIGH);
  delay(5555) ;
  digitalWrite(10,LOW);
  SPIout(0x03);
  SPIout(~0xAA);
  digitalWrite(10,HIGH);
  delay(5555) ;
}

Bouncing ball

The last extension of this test C suite was to have a single dot bounce around. 

.. same #defines as previous version...
byte CSS = 10 ;  // the ChipSelect pin

// Variables
byte BallXcurr, BallYcurr ; // last, current position [0,15/1,8]
byte BallXdir, BallYdir ; // just +/- for 45 degrees motion [0,1]

void SPIout ( byte Bits ) {
  // Output a byte to SPI - block until complete
  SPDR = Bits ;
  while(!(SPSR & (1<<SPIF)) ) ; // Wait until complete
}

void RowSet ( byte RowNum, unsigned int RowBits ) {
  // Fill a whole row (16 bits)
  digitalWrite(CSS,LOW);
  SPIout(RowNum) ; SPIout(RowBits&0xff) ;
  SPIout(RowNum) ; SPIout(RowBits>>8) ;
  digitalWrite(CSS,HIGH);
}

void setup() {
  pinMode(11,OUTPUT); pinMode(13,OUTPUT) ;
  // Direct manipulation: DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK); // Set MOSI and SCK output, all others input
  // (to be nicer it should mask the other pins, ie not change them)
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); // Enable SPI, Controller, set clock rate fck/16
  pinMode(10,OUTPUT); // Ready the chip select
  BallXcurr = 5 ; BallYcurr = 5 ;
}

void loop() {
  RowSet(BallYcurr,0x00) ; // extinguish current position
  if ( BallXcurr==0 ) BallXdir=1 ; if ( BallXcurr==15 ) BallXdir=0 ; // bounce if needed
  if ( BallXdir==1 ) BallXcurr++ ; else BallXcurr-- ; // advance
  if ( BallYcurr==1 ) BallYdir=1 ; if ( BallYcurr==8 ) BallYdir=0 ; // bounce if needed
  if ( BallYdir==1 ) BallYcurr++ ; else BallYcurr-- ; // advance
  RowSet(BallYcurr,1<<BallXcurr) ;
  delay(33);
}

I spent a little more time on this, partly with finding out the up/down, numbering starting at 0 or 1, and other minor details. (We all know the devil is in the details, right?)  Sorry about the the code not being effective, pretty or educational, it is just a quick ProofOfConcept. Works in the simulator (havn't build the hardware yet)

Next ...?

Well, I do not really want to write the whole game in C. If I continue this it will be to include the button reading in a loop. Involving interrupts is also possible. So there may come a Part 2 or maybe not.

Discussions