找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1555|回复: 1
打印 上一主题 下一主题
收起左侧

Silicon Labs给的例程不能成功写入SPI EEPRom

[复制链接]
跳转到指定楼层
楼主
ID:125676 发表于 2018-3-15 16:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. //-----------------------------------------------------------------------------
  2. // F500_SPI0_EEPROM_Polled_Mode.c
  3. //-----------------------------------------------------------------------------
  4. // Copyright 2008 Silicon Laboratories, Inc.
  5. //
  6. // Program Description:
  7. //
  8. // This program accesses a SPI EEPROM using polled mode access. The 'F500 MCU
  9. // is configured in 4-wire Single Master Mode, and the EEPROM is the only
  10. // slave device connected to the SPI bus. The read/write operations are
  11. // tailored to access a Microchip 4 kB EEPROM 25LC320. The relevant hardware
  12. // connections of the 'F500 MCU are shown here:
  13. //
  14. // P0.0 - SPI SCK    (digital output, push-pull)
  15. // P0.1 - SPI MISO   (digital input,  open-drain)
  16. // P0.2 - SPI MOSI   (digital output, push-pull)
  17. // P0.3 - SPI NSS    (digital output, push-pull)
  18. // P0.4 - UART TXD   (digital output, push-pull)
  19. // P0.5 - UART RXD   (digital input,  open-drain)
  20. // P1.3 - LED        (digital output, push-pull)
  21. //
  22. //
  23. // How To Test:
  24. //
  25. // Method1:
  26. // 1) Download the code to a 'F500 device that is connected as above.
  27. // 2) Run the code. The LED will blink fast during the write/read/verify
  28. //    operations.
  29. // 3) If the verification passes, the LED will blink slowly. If it fails,
  30. //    the LED will be OFF.
  31. //
  32. // Method2 (optional):
  33. // 1) Download code to a 'F500 device that is connected as above
  34. // 2) Connect USB cable from the development board to a PC
  35. // 3) On the PC, open HyperTerminal (or any other terminal program) and connect
  36. //    to the USB port (virtual com port) at <BAUDRATE>, 8 data bits, no parity,
  37. //    1 stop bit, no flow control.
  38. // 4) HyperTerminal will print the progress of the write/read operation, and in
  39. //    the end will print the test result as pass or fail. Additionally, if the
  40. //    verification passes, the LED will blink slowly. If it fails, the LED will
  41. //    be OFF.
  42. //
  43. //
  44. // Target:         C8051F500 (Side A of a C8051F500-TB)
  45. // Tool chain:     Keil C51 8.0 / Keil EVAL C51
  46. // Command Line:   None
  47. //
  48. // Release 1.0 / 06 MAR 2008 (GP)
  49. //    -Initial Revision
  50. //

  51. //-----------------------------------------------------------------------------
  52. // Includes
  53. //-----------------------------------------------------------------------------

  54. #include <compiler_defs.h>
  55. #include <C8051F500_defs.h>            // SFR declarations
  56. #include <stdio.h>                     // printf is declared here

  57. //-----------------------------------------------------------------------------
  58. // Global Constants
  59. //-----------------------------------------------------------------------------
  60. #define BAUDRATE           115200      // Baud rate of UART in bps
  61. #define SYSCLK             24000000    // Internal oscillator frequency in Hz

  62. // Microchip 25AA320 Slave EEPROM Parameters
  63. #define  F_SCK_MAX         2000000     // Max SCK freq (Hz)
  64. #define  T_NSS_DISABLE_MIN 500         // Min NSS disable time (ns)
  65. #define  EEPROM_CAPACITY   4096        // EEPROM capacity (bytes)

  66. // EEPROM Instruction Set
  67. #define  EEPROM_CMD_READ   0x03        // Read Command
  68. #define  EEPROM_CMD_WRITE  0x02        // Write Command
  69. #define  EEPROM_CMD_WRDI   0x04        // Reset Write Enable Latch Command
  70. #define  EEPROM_CMD_WREN   0x06        // Set Write Enable Latch Command
  71. #define  EEPROM_CMD_RDSR   0x05        // Read Status Register Command
  72. #define  EEPROM_CMD_WRSR   0x01        // Write Status Register Command

  73. SBIT (LED, SFR_P1, 3);                 // LED==1 means ON

  74. //-----------------------------------------------------------------------------
  75. // Function Prototypes
  76. //-----------------------------------------------------------------------------

  77. void PCA0_Init (void);
  78. void OSCILLATOR_Init (void);
  79. void PORT_Init (void);
  80. void TIMER2_Init (void);
  81. void UART0_Init (void);
  82. void SPI0_Init (void);
  83. void Init_Device (void);

  84. void Delay_us (U8 time_us);
  85. void Delay_ms (U8 time_ms);
  86. void EEPROM_Write (U16 address, U8 value);
  87. U8 EEPROM_Read (U16 address);

  88. //-----------------------------------------------------------------------------
  89. // main() Routine
  90. //-----------------------------------------------------------------------------
  91. void main (void)
  92. {
  93.    U16 address;                        // EEPROM address
  94.    U8 test_byte;                       // Used as a temporary variable

  95.    Init_Device ();                     // Initializes hardware peripherals


  96.    // The following code will test the EEPROM by performing write/read/verify
  97.    // operations. The first test will write 0xFFs to the EEPROM, and the
  98.    // second test will write the LSBs of the EEPROM addresses.

  99.    SFRPAGE = ACTIVE_PAGE;              // Set for printf()

  100.    // Fill EEPROM with 0xFF's
  101.    LED = 1;
  102.    printf("Filling with 0xFF's...\n");
  103.    for (address = 0; address < EEPROM_CAPACITY; address++)
  104.    {
  105.       test_byte = 0xFF;
  106.       EEPROM_Write (address, test_byte);

  107.       // Print status to UART0
  108.       if ((address % 16) == 0)
  109.       {
  110.          printf ("\nWriting 0x%04x: %02x ", address, (U16)test_byte);
  111.          LED = !LED;
  112.       }
  113.       else
  114.       {
  115.          printf ("%02x ", (U16)test_byte);
  116.       }
  117.    }

  118.    // Verify EEPROM with 0xFF's
  119.    printf("\n\nVerifying 0xFF's...\n");
  120.    for (address = 0; address < EEPROM_CAPACITY; address++)
  121.    {
  122.       test_byte = EEPROM_Read (address);

  123.       // Print status to UART0
  124.       if ((address % 16) == 0)
  125.       {
  126.          printf ("\nVerifying 0x%04x: %02x ", address, (U16)test_byte);
  127.          LED = !LED;
  128.       }
  129.       else
  130.       {
  131.          printf ("%02x ", (U16)test_byte);
  132.       }

  133.       if (test_byte != 0xFF)
  134.       {
  135.          LED = 0;
  136.          printf ("Error at %u\n", address);
  137.          while (1);                    // Stop here on error (for debugging)
  138.       }
  139.    }

  140.    // Fill EEPROM with LSB of EEPROM addresses
  141.    printf("\n\nFilling with LSB of EEPROM addresses...\n");
  142.    for (address = 0; address < EEPROM_CAPACITY; address++)
  143.    {
  144.       test_byte = address & 0xFF;
  145.       EEPROM_Write (address, test_byte);

  146.       // Print status to UART0
  147.       if ((address % 16) == 0)
  148.       {
  149.          printf ("\nWriting 0x%04x: %02x ", address, (U16)test_byte);
  150.          LED = !LED;
  151.       }
  152.       else
  153.       {
  154.          printf ("%02x ", (U16)test_byte);
  155.       }
  156.    }

  157.    // Verify EEPROM with LSB of EEPROM addresses
  158.    printf("\n\nVerifying LSB of EEPROM addresses...\n");
  159.    for (address = 0; address < EEPROM_CAPACITY; address++)
  160.    {
  161.       test_byte = EEPROM_Read (address);

  162.       // print status to UART0
  163.       if ((address % 16) == 0)
  164.       {
  165.          printf ("\nVerifying 0x%04x: %02x ", address, (U16)test_byte);
  166.          LED = !LED;
  167.       }
  168.       else
  169.       {
  170.          printf ("%02x ", (U16)test_byte);
  171.       }

  172.       if (test_byte != (address & 0xFF))
  173.       {
  174.          LED = 0;
  175.          printf ("Error at %u\n", address);
  176.          while (1);                    // Stop here on error (for debugging)
  177.       }
  178.    }

  179.    printf ("\n\nVerification success!\n");

  180.    while (1)                           // Loop forever
  181.    {
  182.       LED = !LED;                      // Flash LED when done (all verified)
  183.       Delay_ms (200);
  184.    }
  185. }

  186. //-----------------------------------------------------------------------------
  187. // Initialization Subroutines
  188. //-----------------------------------------------------------------------------

  189. //-----------------------------------------------------------------------------
  190. // PCA0_Init
  191. //-----------------------------------------------------------------------------
  192. //
  193. // Return Value : None
  194. // Parameters   : None
  195. //
  196. // This function disables the watchdog timer.
  197. //
  198. //-----------------------------------------------------------------------------
  199. void PCA0_Init (void)
  200. {
  201.    U8 SFRPAGE_save = SFRPAGE;
  202.    SFRPAGE = ACTIVE_PAGE;

  203.    PCA0MD   &= ~0x40;

  204.    SFRPAGE = SFRPAGE_save;
  205. }

  206. //-----------------------------------------------------------------------------
  207. // OSCILLATOR_Init
  208. //-----------------------------------------------------------------------------
  209. //
  210. // Return Value : None
  211. // Parameters   : None
  212. //
  213. // This function initializes the system clock to use the internal oscillator
  214. // at 24 MHz.
  215. //
  216. //-----------------------------------------------------------------------------
  217. void OSCILLATOR_Init (void)
  218. {
  219.    U8 SFRPAGE_save = SFRPAGE;
  220.    SFRPAGE = CONFIG_PAGE;

  221.    OSCICN   = 0x87;

  222.    SFRPAGE = SFRPAGE_save;
  223. }

  224. //-----------------------------------------------------------------------------
  225. // PORT_Init
  226. //-----------------------------------------------------------------------------
  227. //
  228. // Return Value : None
  229. // Parameters   : None
  230. //
  231. // This function configures the crossbar and GPIO ports.
  232. //
  233. // P0.0  -  SCK  (SPI0), Push-Pull,  Digital
  234. // P0.1  -  MISO (SPI0), Open-Drain, Digital
  235. // P0.2  -  MOSI (SPI0), Push-Pull,  Digital
  236. // P0.3  -  NSS  (SPI0), Push-Pull,  Digital
  237. // P0.4  -  TX0 (UART0), Push-Pull,  Digital
  238. // P0.5  -  RX0 (UART0), Open-Drain, Digital
  239. //
  240. // P1.3  -  Skipped,     Push-Pull,  Digital (LED D2 on Target Board)
  241. // P1.4  -  Skipped,     Open-Drain, Digital (Switch S2 on Target Board)
  242. //
  243. //-----------------------------------------------------------------------------
  244. void PORT_Init (void)
  245. {
  246.    U8 SFRPAGE_save = SFRPAGE;
  247.    SFRPAGE = CONFIG_PAGE;

  248.    P0MDOUT  = 0x1D;                    // Configure P0.0/2/3/4 to push-pull
  249.    P1MDOUT  = 0x08;                    // Configure P1.3 to push-pull

  250.    P1SKIP   = 0x18;                    // Skip P1.3 and P1.4 on the crossbar

  251.    XBR0     = 0x05;                    // Enable SPI and UART0 on crossbar
  252.    XBR2     = 0x40;                    // Enable crossbar

  253.    SFRPAGE = SFRPAGE_save;
  254. }

  255. //-----------------------------------------------------------------------------
  256. // TIMER2_Init
  257. //-----------------------------------------------------------------------------
  258. //
  259. // Return Value : None
  260. // Parameters   : None
  261. //
  262. // Initializes Timer2 to be clocked by SYSCLK for use as a delay timer.
  263. //
  264. //-----------------------------------------------------------------------------
  265. void TIMER2_Init (void)
  266. {
  267.    // CKCON is available on all pages

  268.    CKCON    |= 0x10;
  269. }

  270. //-----------------------------------------------------------------------------
  271. // UART0_Init
  272. //-----------------------------------------------------------------------------
  273. //
  274. // Return Value : None
  275. // Parameters   : None
  276. //
  277. // Configure the UART0 using Baudrate generator, for <BAUDRATE1> and 8-N-1.
  278. //
  279. //-----------------------------------------------------------------------------
  280. void UART0_Init (void)
  281. {
  282.    U8 SFRPAGE_save = SFRPAGE;
  283.    SFRPAGE = CONFIG_PAGE;

  284.    SCON0 = 0x10;                       // SCON0: 8-bit variable bit rate
  285.                                        // clear RI0 and TI0 bits

  286.   // Baud Rate = [BRG Clock / (65536 - (SBRLH0:SBRLL0))] x 1/2 x 1/Prescaler

  287. #if   ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 1)
  288.       SBRL0 = -(SYSCLK / BAUDRATE / 2);
  289.       SBCON0 |= 0x03;                  // Set prescaler to 1
  290. #elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 4)
  291.       SBRL0 = -(SYSCLK / BAUDRATE / 2 / 4);
  292.       SBCON0 &= ~0x03;
  293.       SBCON0 |= 0x01;                  // Set prescaler to 4
  294. #elif ((SYSCLK / BAUDRATE / 2 / 0xFFFF) < 12)
  295.       SBRL0 = -(SYSCLK / BAUDRATE / 2 / 12);
  296.       SBCON0 &= ~0x03;                 // Set prescaler to 12
  297. #else
  298.       SBRL0 = -(SYSCLK / BAUDRATE / 2 / 48);
  299.       SBCON0 &= ~0x03;
  300.       SBCON0 |= 0x02;                  // Set prescaler to 48
  301. #endif

  302.    SBCON0 |= 0x40;                     // Enable baud rate generator

  303.    TI0 = 1;                            // Indicate TX0 ready

  304.    SFRPAGE = SFRPAGE_save;
  305. }

  306. //-----------------------------------------------------------------------------
  307. // SPI0_Init
  308. //-----------------------------------------------------------------------------
  309. //
  310. // Return Value : None
  311. // Parameters   : None
  312. //
  313. // Configures SPI0 to use 4-wire Single-Master mode. The SPI timing is
  314. // configured for Mode 0,0 (data centered on first edge of clock phase and
  315. // SCK line low in idle state). The SPI clock is set to 1.75 MHz. The NSS pin
  316. // is set to 1.
  317. //
  318. //-----------------------------------------------------------------------------
  319. void SPI0_Init()
  320. {
  321.    U8 SFRPAGE_save = SFRPAGE;
  322.    SFRPAGE = ACTIVE_PAGE;

  323.    SPI0CFG   = 0x40;                   // Enable the SPI as a Master
  324.                                        // CKPHA = '0', CKPOL = '0'

  325.    SPI0CN    = 0x0D;                   // 4-wire, single master mode
  326.                                        // SPI0 enable

  327.    // The equation for SPI0CKR is (SYSCLK/(2*F_SCK_MAX))-1, but this yields
  328.    // a SPI frequency that is slightly more than 2 MHz. But, 2 MHz is the max
  329.    // frequency spec of the EEPROM used here. So, the "-1" term is omitted
  330.    // in the following usage:
  331.    SPI0CKR   = (SYSCLK / (2 * F_SCK_MAX));

  332.    SFRPAGE = SFRPAGE_save;
  333. }

  334. //-----------------------------------------------------------------------------
  335. // Init_Device
  336. //-----------------------------------------------------------------------------
  337. //
  338. // Return Value : None
  339. // Parameters   : None
  340. //
  341. // Calls all device initialization functions.
  342. //
  343. //-----------------------------------------------------------------------------
  344. void Init_Device (void)
  345. {
  346.    PCA0_Init ();
  347.    OSCILLATOR_Init ();
  348.    PORT_Init ();
  349.    TIMER2_Init ();
  350.    UART0_Init ();
  351.    SPI0_Init ();
  352. }

  353. //-----------------------------------------------------------------------------
  354. // Support Subroutines
  355. //-----------------------------------------------------------------------------

  356. //-----------------------------------------------------------------------------
  357. // Delay_us
  358. //-----------------------------------------------------------------------------
  359. //
  360. // Return Value : None
  361. // Parameters   : 1. time_us - time delay in microseconds
  362. //                   range: 1 to 255
  363. //
  364. // Creates a delay for the specified time (in microseconds) using TIMER2. The
  365. // time tolerance is approximately +/-50 ns (1/SYSCLK + function call time).
  366. //
  367. //-----------------------------------------------------------------------------
  368. void Delay_us (U8 time_us)
  369. {
  370.    U8 SFRPAGE_save = SFRPAGE;
  371.    SFRPAGE = ACTIVE_PAGE;

  372.    TR2   = 0;                          // Stop timer
  373.    TF2H  = 0;                          // Clear timer overflow flag
  374.    TMR2  = -((U16)(SYSCLK / 1000000) * (U16)(time_us));
  375.    TR2   = 1;                          // Start timer
  376.    while (!TF2H);                      // Wait till timer overflow occurs
  377.    TR2   = 0;                          // Stop timer

  378.    SFRPAGE = SFRPAGE_save;
  379. }

  380. //-----------------------------------------------------------------------------
  381. // Delay_ms
  382. //-----------------------------------------------------------------------------
  383. //
  384. // Return Value : None
  385. // Parameters   : 1. time_ms - time delay in milliseconds
  386. //                   range: 1 to 255
  387. //
  388. // Creates a delay for the specified time (in milliseconds) using TIMER2. The
  389. // time tolerance is approximately +/-50 ns (1/SYSCLK + function call time).
  390. //
  391. //-----------------------------------------------------------------------------
  392. void Delay_ms (U8 time_ms)
  393. {
  394.    U8 i;

  395.    while(time_ms--)
  396.    {
  397.       for(i = 0; i< 10; i++)           // 10 * 100 microsecond delay
  398.       {         
  399.          Delay_us (100);
  400.       }
  401.    }
  402. }

  403. //-----------------------------------------------------------------------------
  404. // EEPROM_Write
  405. //-----------------------------------------------------------------------------
  406. //
  407. // Return Value : None
  408. // Parameters   : 1. address - the destination EEPROM address.
  409. //                   range: 0 to EEPROM_CAPACITY
  410. //                2. value - the value to write.
  411. //                   range: 0x00 to 0xFF
  412. //
  413. // Writes one byte to the specified address in the EEPROM. This function polls
  414. // the EEPROM status register after the write operation, and returns only after
  415. // the status register indicates that the write cycle is complete. This is to
  416. // prevent from having to check the status register before a read operation.
  417. //
  418. //-----------------------------------------------------------------------------
  419. void EEPROM_Write (U16 address, U8 value)
  420. {
  421.    U8 SFRPAGE_save = SFRPAGE;
  422.    SFRPAGE = ACTIVE_PAGE;

  423.    // Writing a byte to the EEPROM is a five-step operation.

  424.    // Step1: Set the Write Enable Latch to 1
  425.    NSSMD0   = 0;                       // Step1.1: Activate Slave Select
  426.    SPI0DAT  = EEPROM_CMD_WREN;         // Step1.2: Send the WREN command
  427.    while (!SPIF);                      // Step1.3: Wait for end of transfer
  428.    SPIF     = 0;                       // Step1.4: Clear the SPI intr. flag
  429.    NSSMD0   = 1;                       // Step1.5: Deactivate Slave Select
  430.    Delay_us (1);                       // Step1.6: Wait for at least
  431.                                        //          T_NSS_DISABLE_MIN
  432.    // Step2: Send the WRITE command
  433.    NSSMD0   = 0;
  434.    SPI0DAT  = EEPROM_CMD_WRITE;
  435.    while (!SPIF);
  436.    SPIF     = 0;

  437.    // Step3: Send the EEPROM destination address (MSB first)
  438.    SPI0DAT  = (U8)((address >> 8) & 0x00FF);
  439.    while (!SPIF);
  440.    SPIF     = 0;
  441.    SPI0DAT  = (U8)(address & 0x00FF);
  442.    while (!SPIF);
  443.    SPIF     = 0;

  444.    // Step4: Send the value to write
  445.    SPI0DAT  = value;
  446.    while (!SPIF);
  447.    SPIF     = 0;
  448.    NSSMD0   = 1;
  449.    Delay_us (1);

  450.    // Step5: Poll on the Write In Progress (WIP) bit in Read Status Register
  451.    do
  452.    {
  453.       NSSMD0   = 0;                    // Activate Slave Select
  454.       SPI0DAT  = EEPROM_CMD_RDSR;      // Send the Read Status Register command
  455.       while (!SPIF);                   // Wait for the command to be sent out
  456.       SPIF     = 0;
  457.       SPI0DAT  = 0;                    // Dummy write to output serial clock
  458.       while (!SPIF);                   // Wait for the register to be read
  459.       SPIF     = 0;
  460.       NSSMD0   = 1;                    // Deactivate Slave Select after read
  461.       Delay_us (1);
  462.    } while((SPI0DAT & 0x01) == 0x01);

  463.    SFRPAGE = SFRPAGE_save;
  464. }

  465. //-----------------------------------------------------------------------------
  466. // EEPROM_Read
  467. //-----------------------------------------------------------------------------
  468. //
  469. // Return Value : The value that was read from the EEPROM
  470. //                   range: 0x00 to 0xFF
  471. // Parameters   : 1. address - the source EEPROM address.
  472. //                   range: 0 to EEPROM_CAPACITY
  473. //
  474. // Reads one byte from the specified EEPROM address.
  475. //
  476. //-----------------------------------------------------------------------------
  477. U8 EEPROM_Read (U16 address)
  478. {
  479.    U8 spi_data;

  480.    U8 SFRPAGE_save = SFRPAGE;
  481.    SFRPAGE = ACTIVE_PAGE;

  482.    // Reading a byte from the EEPROM is a three-step operation.

  483.    // Step1: Send the READ command
  484.    NSSMD0   = 0;                       // Activate Slave Select
  485.    SPI0DAT  = EEPROM_CMD_READ;
  486.    while (!SPIF);
  487.    SPIF     = 0;

  488.    // Step2: Send the EEPROM source address (MSB first)
  489.    SPI0DAT  = (U8)((address >> 8) & 0x00FF);
  490.    while (!SPIF);
  491.    SPIF     = 0;
  492.    SPI0DAT  = (U8)(address & 0x00FF);
  493.    while (!SPIF);
  494.    SPIF     = 0;

  495.    // Step3: Read the value returned
  496.    SPI0DAT  = 0;                       // Dummy write to output serial clock
  497.    while (!SPIF);                      // Wait for the value to be read
  498.    SPIF     = 0;
  499.    NSSMD0   = 1;                       // Deactivate Slave Select
  500.    Delay_us (1);

  501.    spi_data = SPI0DAT;                 // Read data before restoring SFR page

  502.    SFRPAGE = SFRPAGE_save;

  503.    return spi_data;
  504. }

  505. #ifdef SDCC

  506. // SDCC does not include a definition for putchar(), which is used in printf()
  507. // and so it is defined here.  The prototype does not need to be explicitly
  508. // defined because it is provided in stdio.h

  509. //-----------------------------------------------------------------------------
  510. // putchar
  511. //-----------------------------------------------------------------------------
  512. //
  513. // Return Value : None
  514. // Parameters   : character to send to UART
  515. //
  516. // This function outputs a character to the UART.
  517. //-----------------------------------------------------------------------------
  518. void putchar (char input)
  519. {
  520.    if (output == '\n')
  521.    {
  522.       while (!TI0);
  523.       TI0 = 0;
  524.       SBUF0 = 0x0d;
  525.    }
  526.    while (!TI0);
  527.    TI0 = 0;
  528.    SBUF0 = output;
  529. }

  530. #endif

  531. //-----------------------------------------------------------------------------
  532. // End Of File
  533. //-----------------------------------------------------------------------------


复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:125676 发表于 2018-3-15 16:23 | 只看该作者
顶起来!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表