Main Page | File List | Globals | Related Pages

spi.c

Go to the documentation of this file.
00001 /* 00002 * $Id: spi.c,v 1.3 2003/12/02 08:25:00 troth Exp $ 00003 * 00004 **************************************************************************** 00005 * 00006 * simulavr - A simulator for the Atmel AVR family of microcontrollers. 00007 * Copyright (C) 2003 Keith Gudger 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 * 00023 **************************************************************************** 00024 */ 00025 00026 /** 00027 * \file spi.c 00028 * \brief Module to simulate the AVR's SPI module. 00029 * 00030 */ 00031 00032 #include <config.h> 00033 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 00037 #include "avrerror.h" 00038 #include "avrmalloc.h" 00039 #include "avrclass.h" 00040 #include "utils.h" 00041 #include "callback.h" 00042 #include "op_names.h" 00043 00044 #include "storage.h" 00045 #include "flash.h" 00046 00047 #include "vdevs.h" 00048 #include "memory.h" 00049 #include "stack.h" 00050 #include "register.h" 00051 #include "sram.h" 00052 #include "eeprom.h" 00053 #include "timers.h" 00054 #include "ports.h" 00055 #include "spi.h" 00056 00057 #include "avrcore.h" 00058 00059 #include "intvects.h" 00060 00061 /****************************************************************************\ 00062 * 00063 * SPI Interrupts 00064 * 00065 \****************************************************************************/ 00066 00067 static uint8_t spi_intr_read (VDevice *dev, int addr); 00068 static void spi_intr_write (VDevice *dev, int addr, uint8_t val); 00069 static void spi_intr_reset (VDevice *dev); 00070 static char *spi_intr_reg_name (VDevice *dev, int addr); 00071 static int spi_intr_cb (uint64_t time, AvrClass *data); 00072 00073 /** \brief Allocate a new SPI interrupt */ 00074 00075 SPIIntr_T * 00076 spi_intr_new (void) 00077 { 00078 SPIIntr_T *spi; 00079 00080 spi = avr_new (SPIIntr_T, 1); 00081 spi_intr_construct (spi); 00082 class_overload_destroy ((AvrClass *)spi, spi_intr_destroy); 00083 00084 return spi; 00085 } 00086 00087 /** \brief Constructor for spi interrupt object. */ 00088 00089 void 00090 spi_intr_construct (SPIIntr_T *spi) 00091 { 00092 char *name = "SPIIntr"; 00093 00094 if (spi == NULL) 00095 avr_error ("passed null ptr"); 00096 00097 vdev_construct ((VDevice *)spi, name, SPI_INTR_BASE, SPI_INTR_SIZE, 00098 spi_intr_read, spi_intr_write, spi_intr_reset, 00099 spi_intr_reg_name); 00100 00101 spi_intr_reset ((VDevice *)spi); 00102 } 00103 00104 /** \brief Destructor for spi interrupt object. */ 00105 00106 void 00107 spi_intr_destroy (void *spi) 00108 { 00109 if (spi == NULL) 00110 return; 00111 00112 vdev_destroy (spi); 00113 } 00114 00115 static uint8_t 00116 spi_intr_read (VDevice *dev, int addr) 00117 { 00118 SPIIntr_T *spi = (SPIIntr_T *)dev; 00119 00120 switch (addr - vdev_get_base (dev)) 00121 { 00122 case SPI_INTR_SPCR_ADDR: 00123 return (spi->spcr); 00124 case SPI_INTR_SPSR_ADDR: 00125 if (spi->spsr & mask_SPIF) 00126 spi->spsr_read |= mask_SPIF; 00127 if (spi->spsr & mask_WCOL) 00128 spi->spsr_read |= mask_WCOL; 00129 return (spi->spsr); 00130 default: 00131 avr_error ("Bad address: 0x%04x", addr); 00132 } 00133 00134 return 0; /* will never get here */ 00135 } 00136 00137 static void 00138 spi_intr_write (VDevice *dev, int addr, uint8_t val) 00139 { 00140 SPIIntr_T *spi = (SPIIntr_T *)dev; 00141 CallBack *cb; 00142 00143 switch (addr - vdev_get_base (dev)) 00144 { 00145 case SPI_INTR_SPCR_ADDR: 00146 spi->spcr = val; 00147 if (spi->spcr & mask_SPE) 00148 { 00149 /* we need to install the intr_cb function */ 00150 cb = callback_new (spi_intr_cb, (AvrClass *)spi); 00151 spi->intr_cb = cb; 00152 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb); 00153 } 00154 else 00155 { 00156 spi->intr_cb = NULL; /* no interrupt are enabled, remove the 00157 callback */ 00158 } 00159 00160 break; 00161 default: 00162 avr_error ("Bad address: 0x%04x", addr); 00163 } 00164 } 00165 00166 static void 00167 spi_intr_reset (VDevice *dev) 00168 { 00169 SPIIntr_T *spi = (SPIIntr_T *)dev; 00170 00171 spi->intr_cb = NULL; 00172 00173 spi->spcr = 0; 00174 spi->spsr = 0; 00175 spi->spsr_read = 0; 00176 } 00177 00178 static char * 00179 spi_intr_reg_name (VDevice *dev, int addr) 00180 { 00181 switch (addr - vdev_get_base (dev)) 00182 { 00183 case SPI_INTR_SPCR_ADDR: 00184 return ("SPCR"); 00185 case SPI_INTR_SPSR_ADDR: 00186 return ("SPSR"); 00187 default: 00188 avr_error ("Bad address: 0x%04x", addr); 00189 } 00190 00191 return NULL; /* will never get here */ 00192 } 00193 00194 static int 00195 spi_intr_cb (uint64_t time, AvrClass *data) 00196 { 00197 SPIIntr_T *spi = (SPIIntr_T *)data; 00198 00199 if (spi->intr_cb == NULL) 00200 return CB_RET_REMOVE; 00201 00202 if ((spi->spcr & mask_SPE) && (spi->spcr & mask_SPIE) 00203 && (spi->spsr & mask_SPIF)) 00204 { 00205 /* an enabled interrupt occured */ 00206 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)spi); 00207 avr_core_irq_raise (core, irq_vect_table_index (SPI_STC)); 00208 spi->spsr &= ~mask_SPIF; 00209 spi->spsr = 0; 00210 } 00211 00212 return CB_RET_RETAIN; 00213 } 00214 00215 /****************************************************************************\ 00216 * 00217 * SPI 00218 * 00219 \****************************************************************************/ 00220 00221 static uint8_t spi_read (VDevice *dev, int addr); 00222 static void spi_write (VDevice *dev, int addr, uint8_t val); 00223 static void spi_reset (VDevice *dev); 00224 static char *spi_reg_name (VDevice *dev, int addr); 00225 static int spi_clk_incr_cb (uint64_t ck, AvrClass *data); 00226 00227 /** \brief Allocate a new SPI structure. */ 00228 00229 SPI_T * 00230 spi_new (void) 00231 { 00232 SPI_T *spi; 00233 00234 spi = avr_new (SPI_T, 1); 00235 spi_construct (spi); 00236 class_overload_destroy ((AvrClass *)spi, spi_destroy); 00237 00238 return spi; 00239 } 00240 00241 /** \brief Constructor for SPI object. */ 00242 00243 void 00244 spi_construct (SPI_T *spi) 00245 { 00246 char *name = "SPI"; 00247 00248 if (spi == NULL) 00249 avr_error ("passed null ptr"); 00250 00251 vdev_construct ((VDevice *)spi, name, SPI_BASE, SPI_SIZE, spi_read, 00252 spi_write, spi_reset, spi_reg_name); 00253 00254 spi_reset ((VDevice *)spi); 00255 } 00256 00257 /** \brief Destructor for SPI object. */ 00258 00259 void 00260 spi_destroy (void *spi) 00261 { 00262 if (spi == NULL) 00263 return; 00264 00265 vdev_destroy (spi); 00266 } 00267 00268 static uint8_t 00269 spi_read (VDevice *dev, int addr) 00270 { 00271 SPI_T *spi = (SPI_T *)dev; 00272 SPIIntr_T *spi_ti; 00273 00274 spi_ti = 00275 (SPIIntr_T *)avr_core_get_vdev_by_name ((AvrCore *) 00276 vdev_get_core ((VDevice *) 00277 spi), 00278 "SPIIntr"); 00279 00280 switch (addr - vdev_get_base (dev)) 00281 { 00282 case SPI_SPDR_ADDR: 00283 if (spi_ti->spsr_read) 00284 { 00285 spi_ti->spsr &= ~spi_ti->spsr_read; 00286 spi_ti->spsr_read = 0; 00287 } 00288 return spi->spdr; 00289 default: 00290 avr_error ("Bad address: 0x%04x", addr); 00291 } 00292 00293 return 0; /* will never get here */ 00294 } 00295 00296 static void 00297 spi_write (VDevice *dev, int addr, uint8_t val) 00298 { 00299 SPI_T *spi = (SPI_T *)dev; 00300 int offset = addr - vdev_get_base (dev); 00301 CallBack *cb; 00302 SPIIntr_T *spi_ti; 00303 00304 spi_ti = 00305 (SPIIntr_T *)avr_core_get_vdev_by_name ((AvrCore *) 00306 vdev_get_core ((VDevice *) 00307 spi), 00308 "SPIIntr"); 00309 00310 if (offset == SPI_SPDR_ADDR) 00311 { 00312 if (spi_ti->spsr_read) 00313 { 00314 spi_ti->spsr &= ~spi_ti->spsr_read; 00315 spi_ti->spsr_read = 0; 00316 } 00317 00318 if (spi->tcnt != 0) 00319 { 00320 spi_ti->spsr |= mask_WCOL; 00321 } 00322 00323 spi->spdr = val; 00324 00325 /* When the user writes to SPDR, a callback is installed for either 00326 clock generated increments or externally generated increments. The 00327 two incrememtor callback are mutally exclusive, only one or the 00328 other can be installed at any given instant. */ 00329 00330 switch ((spi_ti->spcr) & (mask_SPR0 | mask_SPR1)) 00331 { 00332 case SPI_CK_4: 00333 spi->divisor = 4; 00334 break; 00335 case SPI_CK_16: 00336 spi->divisor = 16; 00337 break; 00338 case SPI_CK_64: 00339 spi->divisor = 64; 00340 break; 00341 case SPI_CK_128: 00342 spi->divisor = 128; 00343 break; 00344 default: 00345 avr_error ("The impossible happened!"); 00346 } 00347 00348 /* install the clock incrementor callback (with flair!) */ 00349 if (spi->clk_cb == NULL) 00350 { 00351 cb = callback_new (spi_clk_incr_cb, (AvrClass *)spi); 00352 spi->clk_cb = cb; 00353 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)spi), 00354 cb); 00355 } 00356 spi->tcnt = 8; /* set up timer for 8 clocks */ 00357 spi->spdr_in = spi_port_rd (addr); 00358 } 00359 else 00360 { 00361 avr_error ("Bad address: 0x%04x", addr); 00362 } 00363 } 00364 00365 static void 00366 spi_reset (VDevice *dev) 00367 { 00368 SPI_T *spi = (SPI_T *)dev; 00369 00370 spi->clk_cb = NULL; 00371 00372 spi->spdr = 0; 00373 spi->tcnt = 0; 00374 00375 spi->divisor = 0; 00376 } 00377 00378 static char * 00379 spi_reg_name (VDevice *dev, int addr) 00380 { 00381 switch (addr - vdev_get_base (dev)) 00382 { 00383 case SPI_SPDR_ADDR: 00384 return "SPDR"; 00385 default: 00386 avr_error ("Bad address: 0x%04x", addr); 00387 } 00388 00389 return NULL; 00390 } 00391 00392 static int 00393 spi_clk_incr_cb (uint64_t ck, AvrClass *data) 00394 { 00395 SPI_T *spi = (SPI_T *)data; 00396 uint8_t last = spi->tcnt; 00397 SPIIntr_T *spi_ti; 00398 00399 spi_ti = 00400 (SPIIntr_T *)avr_core_get_vdev_by_name ((AvrCore *) 00401 vdev_get_core ((VDevice *) 00402 spi), 00403 "SPIIntr"); 00404 00405 if (spi->clk_cb == NULL) 00406 return CB_RET_REMOVE; 00407 00408 if (spi->divisor <= 0) 00409 avr_error ("Bad divisor value: %d", spi->divisor); 00410 00411 /* Decrement clock if ck is a mutliple of divisor. Since divisor is always 00412 a power of 2, it's much faster to do the bitwise AND instead of using 00413 the integer modulus operator (%). */ 00414 spi->tcnt -= ((ck & (spi->divisor - 1)) == 0); 00415 00416 if (spi->tcnt != last) /* we've changed the counter */ 00417 { 00418 if (spi->tcnt == 0) 00419 { 00420 spi_ti->spsr |= mask_SPIF; /* spdr is not guaranteed until 00421 operation complete */ 00422 spi_port_wr (spi->spdr); /* tell what we wrote */ 00423 spi->spdr = spi->spdr_in; /* update spdr to what we read */ 00424 00425 return CB_RET_REMOVE; 00426 } 00427 } 00428 00429 return CB_RET_RETAIN; 00430 } 00431 00432 /* FIXME: TRoth/2003-11-28: These will eventually need to be plugged into an 00433 external connection interface. */ 00434 00435 uint8_t 00436 spi_port_rd (int addr) 00437 { 00438 int data; 00439 char line[80]; 00440 00441 while (1) 00442 { 00443 fprintf (stderr, 00444 "\nEnter a byte of hex data to read into the SPI at" 00445 " address 0x%04x: ", addr); 00446 00447 /* try to read in a line of input */ 00448 if (fgets (line, sizeof (line), stdin) == NULL) 00449 continue; 00450 00451 /* try to parse the line for a byte of data */ 00452 if (sscanf (line, "%x\n", &data) != 1) 00453 continue; 00454 00455 break; 00456 } 00457 00458 return (uint8_t) (data & 0xff); 00459 } 00460 00461 void 00462 spi_port_wr (uint8_t val) 00463 { 00464 fprintf (stderr, "wrote 0x%02x to SPI\n", val); 00465 }

Automatically generated by Doxygen 1.3.8 on 11 Aug 2004.