So ill preface this by saying this is most likely wrong, I don't have access to a Logic Analyzer or Oscilloscope (although an LA is on my "Buy next" list). This is in NO way nowhere close to being a "full bitbang library" nor do I want it to be. This is just a super duper simple example for my learning experience to understand timing diagrams (my weak point). I want to understand how SPI works because even though I feel like I get the timing diagram.....im sure i've probably done something wrong. Im still a beginner so this is probably going to be rough looking code. This also is of course only meant to cover Mode 0 (just as a starting point).
This is also just the "master code" currently.
Code Below:
/* * 328p_SPI_BitBang.c * * Created: 11/29/2018 10:59:43 PM * This is only for Mode 0 of SPI and is not meant to be anything but a basic test */ #include <avr/io.h> #include <avr/delay.h> /* Macro's */ #define _BV(bit) (1 << (bit)) /* SPI Port Defines */ #define SCLK PINB4 #define MOSI PINB3 #define MISO PINB2 #define SS PINB1 /* SPI DDR/PINS */ #define SPI_DDR DDRB #define SPI_PORT PORTB #define SPI_PIN PINB #define F_CPU 1000000UL void enable_SPI(void) { SPI_DDR |= 0x1A; /* Set SS/MOSI/SCLK to Output, MISO to Input */ } void ss_low(void) { SPI_PORT &= ~(1 << SS); } void ss_high(void) { SPI_PORT |= (1 << SS); } void sclk_enable(void) { SPI_PORT |= (1 << SCLK); } void sclk_disable(void) { SPI_PORT &= ~(1 << SCLK); } void mosi_high(void) { SPI_PORT |= (1 << MOSI); } void mosi_low(void) { SPI_PORT &= ~(1 << MOSI); } unsigned char transmit_byte(unsigned char data_byte) { int i; char ret_data; ss_low(); /* Set SS Low */ _delay_ms(100); /* SCLK Currently holding low, MOSI is low, SS is low */ for(i = 0; i < 8; i++) { sclk_disable(); //Set Low if(data_byte & 0x80) { mosi_high(); } else { mosi_low(); } /* MOSI Value is latched in */ _delay_ms(10); // Probably unnecessary sclk_enable(); //Send High _delay_ms(10); // Also maybe unnecessary? Im horrible on timing data_byte >>= 1; //I feel like this is wrong? I see people do <<= instead but....don't we want to shift out LSB first each time, and MOSI receives MSB first? if(PINB & MISO) { _BV(8-i-1); //I *think* this is right? we receive MSB first correct? so it should be 7,6,5,4,3,2,1,0? } } ss_high(); // Pull Slave-Select back up sclk_disable(); // Set Clock back to idle (0 in our case for mode 0) return ret_data; } int main(void) { enable_SPI(); /* Set up correct Data Direction Ports */ while (1) { transmit_byte('A'); //Can this convert? } }
Obviously this is just sending a basic byte. Is this ANYWHERE close to being on the right track? I've been looking at timing diagrams and it seems like the data is "there" (I don't know the proper term for it) but maybe "readied?" before the clock signal goes high. It's then sampled and then the clock signal goes low.
I think my biggest confusion is how we control when sampling on the trailing edge vs falling/etc... occurs via Software. I mean I understand what this means on a timing diagram but im not really sure how to control that on the software side (if that makes sense). To me I think (When sending a bit of data, it'll go like this using GPIO pins).
Lets pretend were sending a HIGH logic level (1)
- MOSI is set to 1 on the GPIO pin of choice
- SCLK goes high
- Slave see's SCLK high so it says "We got data!"
- Slave see's a high logic level on MOSI line
- Slave stores that or does w/e with it
- Slave sends back a 1 or 0 on it's MISO line to Master
- Master see's this on MISO line, does whatever it needs to with it.
- SCLK goes low
- Repeat
So to me, this seems like how this would go with the above. I guess since we are sort of "imitating the clock" with a GPIO pin it feels odd to wrap my head around........but I don't see where we can control when MISO/Slave samples the data, I mean it is going to be before the clock GPIO pin goes low...but I suppose it's not really on the trailing edge is it? (Maybe im over-complicating this)
Anyways, thanks for anyone that takes a look and points out what doesn't make any sense (Cause im sure I missed something)
Thanks!