00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <assert.h>
00028 #include <stdio.h>
00029 #include "hwspi.h"
00030 #include "flash.h"
00031 #include "avrdevice.h"
00032 #include "traceval.h"
00033 #include "irqsystem.h"
00034 #include "avrerror.h"
00035
00036
00037 #define SPIE 0x80
00038 #define SPE 0x40
00039 #define DORD 0x20 ///< "When the DORD bit is written to one, the LSB of the data word is transmitted first."
00040 #define MSTR 0x10
00041 #define CPOL 0x08 ///< "When this bit is written to one, SCK is high when idle."
00042 #define CPHA 0x04 ///< When this bit is written to one, output is setup at leading edge and input is sampled trailing edge.
00043 #define SPR1 0x02
00044 #define SPR0 0x01
00045
00046
00047 #define SPIF 0x80
00048 #define WCOL 0x40
00049 #define SPI2X 0x01 //only on mega devices speed x 2
00050
00051
00052
00053
00054 #define SPI_VERBOSE 0
00055
00056 using namespace std;
00057 void HWSpi::spdr_access() {
00058 if (spsr_read) {
00059
00060
00061
00062 spsr&=~(SPIF|WCOL);
00063 spsr_read=false;
00064 }
00065 }
00066
00067 unsigned char HWSpi::GetSPDR() {
00068 spdr_access();
00069 return data_read;
00070 }
00071
00072 unsigned char HWSpi::GetSPSR() {
00073 spsr_read=true;
00074 return spsr;
00075 }
00076
00077 unsigned char HWSpi::GetSPCR() {
00078 return spcr;
00079 }
00080
00081 void HWSpi::SetSPDR(unsigned char val) {
00082 spdr_access();
00083 data_write=val;
00084 if (spcr & MSTR) {
00085 if (bitcnt<8) {
00086 spsr|=WCOL;
00087 } else {
00088 bitcnt=0;
00089 finished=false;
00090 clkcnt=0;
00091 }
00092 }
00093 }
00094
00095 void HWSpi::updatePrescaler() {
00096 int fac2x=(spsr&SPI2X) ? 1 : 2;
00097 switch (spcr & (SPR1|SPR0)) {
00098 case 0: clkdiv=1; break;
00099 case SPR0: clkdiv=4; break;
00100 case SPR1: clkdiv=16; break;
00101 case SPR1|SPR0: clkdiv=32; break;
00102 }
00103 clkdiv*=fac2x;
00104 }
00105
00106 void HWSpi::SetSPSR(unsigned char val) {
00107 if (mega_mode) {
00108 spsr&=~SPI2X;
00109 spsr|=val&SPI2X;
00110 updatePrescaler();
00111 } else {
00112 ((core->trace_on) ?
00113 (traceOut) : (cerr))
00114 << "spsr is read only! (0x" << hex << core->PC << " = " <<
00115 core->Flash->GetSymbolAtAddress(core->PC) << ")" << endl;
00116 }
00117 }
00118
00119
00120 void HWSpi::SetSPCR(unsigned char val) {
00121 spcr=val;
00122 if ( spcr & SPE) {
00123 core->AddToCycleList(this);
00124 if (spcr & MSTR) {
00125 MISO.SetUseAlternateDdr(1);
00126 MISO.SetAlternateDdr(0);
00127 MOSI.SetUseAlternatePortIfDdrSet(1);
00128
00129
00130
00131
00132 MOSI.SetAlternatePort(1);
00133 SCK.SetAlternatePort(spcr & CPOL);
00134 assert(SCK.GetPin().outState == ((spcr & CPOL) ? Pin::HIGH : Pin::LOW));
00135 SCK.SetUseAlternatePortIfDdrSet(1);
00136 assert(SCK.GetPin().outState == ((spcr & CPOL) ? Pin::HIGH : Pin::LOW));
00137 } else {
00138 MISO.SetUseAlternatePortIfDdrSet(1);
00139 MOSI.SetUseAlternateDdr(1);
00140 MOSI.SetAlternateDdr(0);
00141 SCK.SetUseAlternateDdr(1);
00142 SCK.SetAlternateDdr(0);
00143 SS.SetUseAlternateDdr(1);
00144 SS.SetAlternateDdr(0);
00145 }
00146 } else {
00147
00148
00149
00150
00151 bitcnt=8;
00152 finished=false;
00153 core->RemoveFromCycleList(this);
00154 MOSI.SetUseAlternatePortIfDdrSet(0);
00155 MISO.SetUseAlternatePortIfDdrSet(0);
00156 SCK.SetUseAlternatePortIfDdrSet(0);
00157 MOSI.SetUseAlternateDdr(0);
00158 MISO.SetUseAlternateDdr(0);
00159 SCK.SetUseAlternateDdr(0);
00160 SS.SetUseAlternateDdr(0);
00161 }
00162 updatePrescaler();
00163 }
00164
00165
00166 HWSpi::HWSpi(AvrDevice *_c,
00167 HWIrqSystem *_irq,
00168 PinAtPort mosi,
00169 PinAtPort miso,
00170 PinAtPort sck,
00171 PinAtPort ss,
00172 unsigned int ivec,
00173 bool mm) :
00174 Hardware(_c), TraceValueRegister(_c, "SPI"),
00175 core(_c), irq(_irq),
00176 MOSI(mosi), MISO(miso), SCK(sck), SS(ss),
00177 irq_vector(ivec), mega_mode(mm),
00178 spdr_reg(this, "SPDR", this, &HWSpi::GetSPDR, &HWSpi::SetSPDR),
00179 spsr_reg(this, "SPSR", this, &HWSpi::GetSPSR, &HWSpi::SetSPSR),
00180 spcr_reg(this, "SPCR", this, &HWSpi::GetSPCR, &HWSpi::SetSPCR)
00181 {
00182 irq->DebugVerifyInterruptVector(ivec, this);
00183 bitcnt=8;
00184 finished=false;
00185
00186 trace_direct(this, "shift_in", &shift_in);
00187 trace_direct(this, "data_read", &data_read);
00188 trace_direct(this, "data_write", &data_write);
00189 trace_direct(this, "sSPSR", &spsr);
00190 trace_direct(this, "sSPCR", &spcr);
00191 Reset();
00192 }
00193
00194 void HWSpi::Reset() {
00195 SetSPCR(0);
00196 spsr=0;
00197 data_write=data_read=shift_in=0;
00198 }
00199
00200 void HWSpi::ClearIrqFlag(unsigned int vector) {
00201 if (vector==irq_vector) {
00202 spsr&=~SPIF;
00203 irq->ClearIrqFlag(irq_vector);
00204 } else {
00205 cerr << "WARNING: There is HWSPI called to get a irq vector which is not assigned for!?!?!?!?";
00206 }
00207 }
00208
00209 void HWSpi::txbit(const int bitpos) {
00210
00211 PinAtPort *out=(spcr & MSTR) ? &MOSI : &MISO;
00212 out->SetAlternatePort(data_write&(1<<bitpos));
00213 }
00214
00215 void HWSpi::rxbit(const int bitpos) {
00216
00217 bool bit=(spcr & MSTR) ? MISO : MOSI;
00218 if (bit)
00219 shift_in|=(1<<bitpos);
00220 }
00221
00222 void HWSpi::trxend() {
00223 if (finished) {
00224 finished=false;
00225 if (core->trace_on && SPI_VERBOSE)
00226 traceOut << "SPI: READ " << int(shift_in) << endl;
00227
00228
00229 data_write=data_read=shift_in;
00230
00231 spsr|=SPIF;
00232 if (spcr&SPIE) {
00233 irq->SetIrqFlag(this, irq_vector);
00234 }
00235 spsr_read=false;
00236 }
00237 }
00238
00239 unsigned int HWSpi::CpuCycle() {
00240 if ((spcr & SPE) == 0)
00241 return 0;
00242 int bitpos=(spcr&DORD) ? bitcnt : 7-bitcnt;
00243 int bitpos_prec=(spcr&DORD) ? bitcnt-1 : 8-bitcnt;
00244
00245 if (core->trace_on && SPI_VERBOSE) {
00246 traceOut << "SPI: " << bitcnt << ", " << bitpos << ", " << clkcnt << endl;
00247 }
00248
00249 if (spcr & MSTR) {
00250
00251
00252
00253 if (! SS.GetDdr() && ! SS) {
00254 SetSPCR(spcr & ~MSTR);
00255
00256 spsr |= SPIF;
00257 if (spcr&SPIE) {
00258 irq->SetIrqFlag(this, irq_vector);
00259 }
00260 bitcnt = 8;
00261 finished=false;
00262 clkcnt=0;
00263 }
00264 if ((clkcnt%clkdiv) == 0){
00265 if (bitcnt < 8) {
00266 if (bitcnt == 0)
00267 shift_in = 0;
00268 switch ((clkcnt/clkdiv)&1) {
00269 case 0:
00270
00271 SCK.SetAlternatePort(spcr&CPOL);
00272
00273 if (spcr&CPHA) {
00274 if (bitcnt) {
00275 rxbit(bitpos_prec);
00276 }
00277 } else {
00278 txbit(bitpos);
00279 }
00280 break;
00281 case 1:
00282
00283 SCK.SetAlternatePort(!(spcr&CPOL));
00284 if (spcr&CPHA) {
00285 txbit(bitpos);
00286 } else {
00287 rxbit(bitpos);
00288 }
00289 bitcnt++;
00290 break;
00291 }
00292 finished = (bitcnt==8);
00293 } else if (finished) {
00294 if (spcr&CPHA) {
00295 rxbit(bitpos_prec);
00296 }
00297 trxend();
00298
00299 SCK.SetAlternatePort(spcr&CPOL);
00300
00301 if (!(spcr&CPHA))
00302 MOSI.SetAlternatePort(1);
00303 }
00304 }
00305 } else {
00306
00307 if (SS) {
00308
00309 bitcnt=8;
00310 } else {
00311
00312 if (bitcnt == 8) {
00313 bitcnt = 0;
00314 finished = false;
00315 shift_in = 0;
00316 oldsck = SCK;
00317 } else {
00318
00319 if (!(spcr&CPHA)) {
00320 txbit(bitpos);
00321 }
00322 }
00323 if (SCK != oldsck) {
00324 bool leading = false;
00325 if (spcr&CPOL) {
00326
00327 leading = ! SCK;
00328 } else
00329 leading = SCK;
00330
00331
00332 bool sample = leading ^ ((spcr&CPHA)!=0);
00333
00334 if (sample)
00335 rxbit(bitpos);
00336 else
00337 txbit(bitpos);
00338
00339 if (!leading) {
00340 bitcnt++;
00341 finished = (bitcnt==8);
00342 }
00343 }
00344 trxend();
00345 oldsck = SCK;
00346 }
00347 }
00348 clkcnt++;
00349 return 0;
00350 }
00351