/******************************************************************************* * It returns 8 bits vendor ID *******************************************************************************/ uint8_t EEPROM_readVendorId(){ unsigned short r_data = 0; unsigned char r_pcs; spi_write(SPI, RDID, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** SENDING DUMMY ADDRESS ************************/ spi_write(SPI, 0x00, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, 0x00, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, 0x00, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** RECEIVING DATA ************************/ spi_write(SPI, 0x05, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); return r_data; }
/** @ingroup spi_function @brief Send an array of bytes to to the SPI bus. @note Can only be used if SPI_USE_BUFFER are enabled in spi_iha_defs.h @see spi_iha_defs.h for SPI_USE_BUFFER setup. @return SPI_OK: OK byte send to SPI bus or put in tx_buffer.\n SPI_NO_ROOM_IN_TX_BUFFER: Buffer full no data send\n SPI_ILLEGAL_INSTANCE: instance is null. @param spi to send to. @param *buf pointer to buffer to be send. @param len no of bytes to send. */ uint8_t spi_send_bytes(spi_p spi, uint8_t buf[], uint8_t len) { uint8_t result = SPI_OK; uint32_t value; uint8_t tmp = 0; if (spi == NULL) { return SPI_ILLEGAL_INSTANCE; } // Select correct instance if (_this != spi ) { _select_instance(spi); } // Critical section { // disable interrupt spi_disable_interrupt(_spi_base, SPI_IDR_TDRE | SPI_IDR_RDRF); // Check if buffer is free if (len > fifo_get_free_size(spi->_spi_tx_fifo_desc)) { result = SPI_NO_ROOM_IN_TX_BUFFER; } else { // If SPI in idle send the first byte if (!_spi_active) { _spi_active = 1; // Send first byte value = SPI_TDR_TD(buf[0]) | SPI_TDR_PCS(spi_get_pcs(spi->_cs_pin)); if (len == 1) { // It was last byte value |= SPI_TDR_LASTXFER; } // Send byte _spi_base->SPI_TDR = value; //spi_enable_interrupt(_spi_base, SPI_IER_TDRE); tmp = 1; } // Put in the tx buffer for (uint8_t i = tmp; i < len; i++) { value = SPI_TDR_TD(buf[i]) | SPI_TDR_PCS(spi_get_pcs(spi->_cs_pin)); if (i == len-1) { // It was last byte value |= SPI_TDR_LASTXFER; } if ( fifo_push_uint32(spi->_spi_tx_fifo_desc, value) == FIFO_ERROR_OVERFLOW ) { result = SPI_NO_ROOM_IN_TX_BUFFER; } } } // restore interrupt state spi_enable_interrupt(_spi_base, SPI_IER_TDRE | SPI_IER_RDRF); } return result; }
/******************************************************************************* * WRITE EEPROM STATUS BYTE * | W/R|| _ | _ | _ | W/R | W/R | R | R | * | WPEN| X | X | X | BP1 | BP0 | WEL | WIP | *******************************************************************************/ void _EEPROM_writeStatusReg(uint8_t w_status){ unsigned char r_pcs; uint8_t r_data = 0; spi_write(SPI, WRSR, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, w_status, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); }
/******************************************************************************* * READ EEPROM STATUS BYTE * | W/R|| _ | _ | _ | W/R | W/R | R | R | * | WPEN| X | X | X | BP1 | BP0 | WEL | WIP | *******************************************************************************/ uint8_t _EEPROM_readStatusReg(){ unsigned char r_pcs; uint8_t r_data = 0; spi_write(SPI, RDSR, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, 0x00, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); return r_data; }
/******************************************************************************* * DEEP POWER DOWN MODE *******************************************************************************/ void EEPROM_powerDownMode(){ unsigned short r_data = 0; unsigned char r_pcs; spi_write(SPI, DPD, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); }
/******************************************************************************* * DISABLE WRITE EEPROM LATCH *******************************************************************************/ void _EEPROM_wrdi(){ unsigned short r_data = 0; unsigned char r_pcs; spi_write(SPI, WRDI, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); }
/******************************************************************************* * The Chip Erase function will erase all bits (0xFF) in the array. * * While the device is executing the chipErase() function, the WriteInProcess() * macro can be read to determine when the Chip Erase function is complete. * *******************************************************************************/ void EEPROM_chipErase(){ unsigned short r_data = 0; unsigned char r_pcs; _EEPROM_wren(); spi_write(SPI, CE, spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); }
/** * \brief Initialize SPI as master. */ static void spi_master_initialize(void) { /* Configure an SPI peripheral. */ uint32_t spi_chip_sel, spi_clk_freq, spi_clk_pol, spi_clk_pha; spi_enable_clock(SPI_MASTER_BASE); spi_reset(SPI_MASTER_BASE); spi_set_master_mode(SPI_MASTER_BASE); spi_disable_mode_fault_detect(SPI_MASTER_BASE); spi_disable_loopback(SPI_MASTER_BASE); spi_set_peripheral_chip_select_value(SPI_MASTER_BASE, spi_get_pcs(2)); // This sets the value of PCS within the Mode Register. spi_set_variable_peripheral_select(SPI_MASTER_BASE); // PCS needs to be set within each transfer (PCS within SPI_TDR). spi_disable_peripheral_select_decode(SPI_MASTER_BASE); // Each CS is to be connected to a single device. spi_set_delay_between_chip_select(SPI_MASTER_BASE, SPI_DLYBCS); /* Set communication parameters for CS0 */ spi_chip_sel = 0; spi_clk_freq = 100000; // SPI CLK for RTC = 100kHz. spi_clk_pol = 1; spi_clk_pha = 0; spi_set_transfer_delay(SPI_MASTER_BASE, spi_chip_sel, SPI_DLYBS, SPI_DLYBCT); spi_set_bits_per_transfer(SPI_MASTER_BASE, spi_chip_sel, SPI_CSR_BITS_16_BIT); spi_set_baudrate_div(SPI_MASTER_BASE, spi_chip_sel, spi_calc_baudrate_div(spi_clk_freq, sysclk_get_cpu_hz())); spi_configure_cs_behavior(SPI_MASTER_BASE, spi_chip_sel, SPI_CS_RISE_FORCED); // CS rises after SPI transfers have completed. spi_set_clock_polarity(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pol); spi_set_clock_phase(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pha); /* Set communication parameters for CS1 */ spi_chip_sel = 1; spi_clk_freq = 2000000; // SPI CLK for RTC = 4MHz. spi_clk_pol = 0; spi_clk_pha = 0; spi_set_transfer_delay(SPI_MASTER_BASE, spi_chip_sel, SPI_DLYBS, SPI_DLYBCT); spi_set_bits_per_transfer(SPI_MASTER_BASE, spi_chip_sel, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(SPI_MASTER_BASE, spi_chip_sel, spi_calc_baudrate_div(spi_clk_freq, sysclk_get_cpu_hz())); spi_configure_cs_behavior(SPI_MASTER_BASE, spi_chip_sel, SPI_CS_RISE_FORCED); spi_set_clock_polarity(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pol); spi_set_clock_phase(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pha); /* Set communication parameters for CS2 */ spi_chip_sel = 2; spi_clk_freq = 44000000; // SPI CLK for MEM2 = 44MHz. spi_clk_pol = 1; spi_clk_pha = 0; spi_set_transfer_delay(SPI_MASTER_BASE, spi_chip_sel, SPI_DLYBS, SPI_DLYBCT); spi_set_bits_per_transfer(SPI_MASTER_BASE, spi_chip_sel, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(SPI_MASTER_BASE, spi_chip_sel, spi_calc_baudrate_div(spi_clk_freq, sysclk_get_cpu_hz())); spi_configure_cs_behavior(SPI_MASTER_BASE, spi_chip_sel, SPI_CS_KEEP_LOW); spi_set_clock_polarity(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pol); spi_set_clock_phase(SPI_MASTER_BASE, spi_chip_sel, spi_clk_pha); /* Enable SPI Communication */ spi_enable(SPI_MASTER_BASE); }
/******************************************************************************* * READ DATA FROM EEPROM * ***** ARGUMENTS ***** * /param reasAdd: EEEPROM address from where it is wanted to start reading * /param data: Pointer of a byte vector variable in which data read is going to be stored * /param dataSize: Size of the vector variable pointed by "data" pointer * * ***** FUNCTIONALITY ***** * readData() reads a frame of 0-137071 data, the start address is specified in "readAdd" argument, * then the function will query as many data as specified by sizeData from EEPROM and will store it * in variable pointed by "data" pointer argument. * * IMPORTANT: there's not knowledge about the limit of data it's allowed to be read in a frame *******************************************************************************/ void EEPROM_readData(uint8_t *readAdd, uint8_t *data, uint32_t dataSize){ unsigned short r_data = 0; unsigned char r_pcs; spi_write(SPI, READ, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** SENDING ADDRESS ************************/ spi_write(SPI, readAdd[2], spi_get_pcs(3), 0); // Address MSB while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, readAdd[1], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, readAdd[0], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** RECEIVING DATA ************************/ for(int i = 0; i<dataSize-1; i++){ spi_write(SPI, 0xAA, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) data, (uint8_t*) &r_pcs); // It receive data in "data" and it's a pointer data++; } spi_write(SPI, 0x55, spi_get_pcs(3), 1); // The las byte must toggle CS while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) data, (uint8_t*) &r_pcs); }
/******************************************************************************* * ERRASE A WHOLE SECTOR OF DATA FROM EPPROM * \param pageAdd: you can write any of the 65535 address into this function and it will erase the whole sector *******************************************************************************/ void EEPROM_sectorErase(uint8_t *sectorAdd){ unsigned short r_data = 0; unsigned char r_pcs; //Command spi_write(SPI, SE, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); //address spi_write(SPI, sectorAdd[2], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, sectorAdd[1], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, sectorAdd[0], spi_get_pcs(3), 1); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); }
spi_p spi_new_instance(Spi * spi_base, uint8_t spi_chip_sel, uint32_t spi_freq, uint8_t spi_mode, uint8_t buffer_size, void(*handler_call_back )(spi_p, uint8_t)) { _spi_base = spi_base; if (!spi_is_enabled(_spi_base)) { _spi_init_base(spi_base); } spi_p _spi = malloc(sizeof *_spi); _spi->_call_back = handler_call_back; _spi->_cs_pin = spi_chip_sel; _spi->_spi_rx_fifo_desc = (fifo_desc_t *)malloc(sizeof(fifo_desc_t)); _spi->_spi_tx_fifo_desc = (fifo_desc_t *)malloc(sizeof(fifo_desc_t)); union spi_buffer_element *spi_tx_fifo_buffer = (union spi_buffer_element *)(malloc(sizeof(union spi_buffer_element) * buffer_size)); union spi_buffer_element *spi_rx_fifo_buffer = (union spi_buffer_element *)(malloc(sizeof(union spi_buffer_element) * buffer_size)); fifo_init(_spi->_spi_rx_fifo_desc, spi_rx_fifo_buffer, buffer_size); fifo_init(_spi->_spi_tx_fifo_desc, spi_tx_fifo_buffer, buffer_size); spi_set_peripheral_chip_select_value(spi_base, spi_get_pcs(spi_chip_sel)); switch (spi_mode) { case 0: spi_set_clock_polarity(spi_base, spi_chip_sel,0); spi_set_clock_phase(spi_base, spi_chip_sel, 1); break; case 1: spi_set_clock_polarity(spi_base, spi_chip_sel, 0); spi_set_clock_phase(spi_base, spi_chip_sel, 0); break; case 2: spi_set_clock_polarity(spi_base, spi_chip_sel, 1); spi_set_clock_phase(spi_base, spi_chip_sel, 1); break; case 3: spi_set_clock_polarity(spi_base, spi_chip_sel, 1); spi_set_clock_phase(spi_base, spi_chip_sel, 0); break; } spi_set_bits_per_transfer(spi_base, spi_chip_sel, SPI_CSR_BITS_8_BIT); spi_configure_cs_behavior(spi_base, spi_chip_sel, SPI_CS_KEEP_LOW); spi_set_baudrate_div(spi_base, spi_chip_sel, (sysclk_get_peripheral_hz() / spi_freq)); spi_set_delay_between_chip_select(spi_base, 0x10); spi_set_transfer_delay(spi_base, spi_chip_sel, 0x01, 0x10); spi_enable(spi_base); return _spi; }
void spi_master_read(void *p_buf, uint32_t size, uint32_t chip_sel) { uint32_t i; uint8_t pcs; pcs = spi_get_pcs(chip_sel); uint16_t data; uint16_t *p_buffer; p_buffer = p_buf; for (i = 0; i < size; i++) { spi_write(SPI_MASTER_BASE, 0, pcs, 0); /* Wait transfer done. */ while ((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RDRF) == 0); spi_read(SPI_MASTER_BASE, &data, &pcs); p_buffer[i] = (uint8_t)data; } }
/** * \brief Perform SPI master transfer. * * \param pbuf Pointer to buffer to transfer. * \param size Size of the buffer. */ void spi_master_transfer(void *p_buf, uint32_t size, uint8_t chip_sel) { uint32_t i = 0; uint8_t pcs; pcs = spi_get_pcs(chip_sel); uint16_t data; uint8_t timeout = 84; // ~1us timeout for getting the read status back. uint16_t *p_buffer; p_buffer = p_buf; if(size == 1) // Only transfer a single message. { spi_write(SPI_MASTER_BASE, p_buffer[i], pcs, 1); // The last parameter above tells SPI whether this is the last byte to be transferred. /* Wait transfer done. */ while ((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RDRF) == 0); spi_read(SPI_MASTER_BASE, &data, &pcs); p_buffer[i] = data; return; } // Keep CS low for the duration of the transfer, set high @ end. for (i = 0; i < (size - 1); i++) { spi_write(SPI_MASTER_BASE, p_buffer[i], pcs, 0); /* Wait transfer done. */ while ((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RDRF) == 0); spi_read(SPI_MASTER_BASE, &data, &pcs); p_buffer[i] = data; delay_us(100); } delay_us(100); spi_write(SPI_MASTER_BASE, p_buffer[(size - 1)], pcs, 1); /* Wait transfer done. */ while ((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RDRF) == 0); spi_read(SPI_MASTER_BASE, &data, &pcs); p_buffer[(size - 1)] = data; return; }
uint8_t spi_send_byte(spi_p spi, uint8_t byte, uint8_t last_byte) { uint8_t result = SPI_OK; uint32_t value; if (spi == NULL) { return SPI_ILLEGAL_INSTANCE; } // Select correct instance if (_this != spi ) { _select_instance(spi); } // Critical section { // disable interrupt spi_disable_interrupt(_spi_base, SPI_IDR_TDRE | SPI_IDR_RDRF); value = SPI_TDR_TD(byte) | SPI_TDR_PCS(spi_get_pcs(spi->_cs_pin)); if (last_byte) { value |= SPI_TDR_LASTXFER; } // If SPI in idle send the byte if (!_spi_active) { _spi_active = 1; // Send byte _spi_base->SPI_TDR = value; } else { // Put in the TX buffer if ( fifo_push_uint32(spi->_spi_tx_fifo_desc, value) == FIFO_ERROR_UNDERFLOW ) result = SPI_NO_ROOM_IN_TX_BUFFER; } // Enable interrupt spi_enable_interrupt(_spi_base, SPI_IER_TDRE | SPI_IER_RDRF); } return result; }
void spi_master_transfer_keepcslow(void *p_buf, uint32_t size, uint8_t chip_sel) { uint32_t i = 0; uint8_t pcs; pcs = spi_get_pcs(chip_sel); uint16_t data; uint16_t *p_buffer; p_buffer = p_buf; // Keep CS low for the duration of the transfer, keep low @ end. for (i = 0; i < size; i++) { spi_write(SPI_MASTER_BASE, p_buffer[i], pcs, 0); /* Wait transfer done. */ while ((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RDRF) == 0); spi_read(SPI_MASTER_BASE, &data, &pcs); p_buffer[i] = data; } return; }
/******************************************************************************* * WRITE DATA FROM EEPROM * ***** ARGUMENTS ***** * /param reasAdd: EEEPROM address where it is wanted to start writing * /param data: Pointer of a byte vector variable in where data to be sent is * /param dataSize: Size of the vector variable pointed by "data" pointer * * ***** FUNCTIONALITY ***** * writeData() writes a frame of 0-137071 data, the start address is specified in "readAdd" argument, * then the function will store as many data as specified by sizeData in EEPROM and will store it * in the variable pointed by "data" pointer argument. * * IMPORTANT: there's not knowledge about the limit of data it's allowed to be read in a frame *******************************************************************************/ void EEPROM_writeData(uint8_t *writeAdd, uint8_t *data, uint8_t dataSize){ unsigned short r_data = 0; unsigned char r_pcs; _EEPROM_wren(); spi_write(SPI, WRITE, spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** SENDING ADDRESS ************************/ spi_write(SPI, writeAdd[2], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, writeAdd[1], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); spi_write(SPI, writeAdd[0], spi_get_pcs(3), 0); while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) &r_data, (uint8_t*) &r_pcs); /**************** SENDING DATA ************************/ for(int i = 0; i<dataSize-1; i++){ spi_write(SPI, *data, spi_get_pcs(3), 0); // It receive data in "data" and it's a pointer while((spi_read_status(SPI) & SPI_SR_RDRF) == 0); spi_read(SPI, (uint16_t*) r_data, (uint8_t*) &r_pcs); data++; } spi_write(SPI, *data, spi_get_pcs(3), 1); // The las byte must toggle CS spi_read(SPI, (uint16_t*) r_data, (uint8_t*) &r_pcs); while( EEPROM_getWriteInProcess() ); // Deberíamos hacer esto aquí pa evitarle el complique al usuario }