/** * \brief Wait the end of busy on DAT0 line * * \return true if success, otherwise false */ static bool sd_mmc_spi_wait_busy(void) { uint8_t line = 0xFF; uint16_t dummy = 0xFF; /* Delay before check busy * Nbr timing minimum = 8 cylces */ spi_read_buffer_wait(&sd_mmc_master, &line, 1, dummy); /* Wait end of busy signal * Nec timing: 0 to unlimited * However a timeout is used. * 200 000 * 8 cycles */ uint32_t nec_timeout = 200000; spi_read_buffer_wait(&sd_mmc_master, &line, 1, dummy); do { spi_read_buffer_wait(&sd_mmc_master, &line, 1, dummy); if (!(nec_timeout--)) { return false; } } while (line != 0xFF); return true; }
/*! * @brief Receives data from BMM050 on SPI * * @param[in] dev_addr Device I2C slave address (not used) * * @param[in] reg_addr Address of destination register * * @param[out] reg_data Pointer to data buffer to be received * * @param[in] length Length of the data to be received * * @retval 0 BMG160_SUCCESS * @retval -1 BMG160_ERROR * */ int8_t bmg_spi_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *rx_data, uint8_t length) { enum status_code bmg_read_stat = STATUS_NO_CHANGE; /* This variable is used to avoid infinite loops. */ uint16_t loop_count; uint16_t dummy = 0; reg_addr = reg_addr | 0x80; spi_select_slave(&spi_master_instance, &bmg160_spi_slave, true); loop_count = 0; do { bmg_read_stat = spi_write_buffer_wait(&spi_master_instance, ®_addr, 1); loop_count++; }while(bmg_read_stat != STATUS_OK && loop_count < 100); loop_count = 0; do { bmg_read_stat = spi_read_buffer_wait(&spi_master_instance, rx_data, length, dummy); loop_count++; }while(bmg_read_stat != STATUS_OK && loop_count < 100); spi_select_slave(&spi_master_instance, &bmg160_spi_slave, false); if (bmg_read_stat != STATUS_OK) { return -1; } return 0; }
/** * \brief Waits the TOKEN which notify the end of write block transfer * * \return true if success, otherwise false * with a update of \ref sd_mmc_spi_err. */ static bool sd_mmc_spi_stop_write_block(void) { uint8_t resp; uint16_t crc; uint16_t dummy = 0xFF; // Send CRC crc = 0xFFFF; /// CRC is disabled in SPI mode spi_write_buffer_wait(&sd_mmc_master, (uint8_t *)&crc, 2); // Receiv data response token spi_read_buffer_wait(&sd_mmc_master, &resp, 1, dummy); if (!SPI_TOKEN_DATA_RESP_VALID(resp)) { sd_mmc_spi_err = SD_MMC_SPI_ERR; sd_mmc_spi_debug("%s: Invalid Data Response Token 0x%x\n\r", __func__, resp); return false; } // Check data response switch (SPI_TOKEN_DATA_RESP_CODE(resp)) { case SPI_TOKEN_DATA_RESP_ACCEPTED: break; case SPI_TOKEN_DATA_RESP_CRC_ERR: sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE_CRC; sd_mmc_spi_debug("%s: Write blocks, SD_MMC_SPI_ERR_CRC, resp 0x%x\n\r", __func__, resp); return false; case SPI_TOKEN_DATA_RESP_WRITE_ERR: default: sd_mmc_spi_err = SD_MMC_SPI_ERR_WRITE; sd_mmc_spi_debug("%s: Write blocks SD_MMC_SPI_ERR_WR, resp 0x%x\n\r", __func__, resp); return false; } return true; }
bool sd_mmc_spi_read_word(uint32_t* value) { uint16_t dummy = 0xFF; sd_mmc_spi_err = SD_MMC_SPI_NO_ERR; Assert(sd_mmc_spi_nb_block > (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size)); if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) { // New block if (!sd_mmc_spi_start_read_block()) { return false; } } // Read data spi_read_buffer_wait(&sd_mmc_master, (uint8_t *)&value, 4, dummy); *value = le32_to_cpu(*value); sd_mmc_spi_transfert_pos += 4; if (!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)) { // End of block sd_mmc_spi_stop_read_block(); } return true; }
int main(void) { //! [main_start] uint8_t result = 0; uint16_t i; uint32_t delay; /* Initialize system */ //! [system_init] system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ); for (i = 0; i < BUF_LENGTH; i++) { buffer_expect[i] = i; buffer_rx[i] = 0; } //! [system_init] //! [run_config_gpio] configure_gpio(); //! [run_config_gpio] //! [run_config_spi] configure_spi_slave(); //! [run_config_spi] //! [main_start] //! [main_use_case] //! [read] memset(buffer_rx, 0x0, BUF_LENGTH); while(spi_read_buffer_wait(&spi_slave_instance, buffer_rx, BUF_LENGTH, 0x00) != STATUS_OK) { /* Wait for transfer from the master */ } //! [read] //! [compare] for (i = 0; i < BUF_LENGTH; i++) { if(buffer_rx[i] != buffer_expect[i]) { result++; } } //! [compare] //! [inf_loop] while (true) { /* Infinite loop */ if (result) { gpio_pin_toggle_output_level(LED_0_PIN); /* Add a short delay to see LED toggle */ delay = 300000; while(delay--) { } } else { gpio_pin_toggle_output_level(LED_0_PIN); /* Add a short delay to see LED toggle */ delay = 3000000; while(delay--) { } } } //! [inf_loop] //! [main_use_case] }
/** * \brief Executed the end of a read block transfer */ static void sd_mmc_spi_stop_read_block(void) { uint8_t crc[2]; uint16_t dummy = 0xFF; // Read 16-bit CRC (not cheked) spi_read_buffer_wait(&sd_mmc_master, crc, 2, dummy); }
/** * \brief Read response on SPI from PC * * return Status * \param[in] rx_buf Pointer to receive the data * \param[in] length The length of the read data * \param[out] rx_buf Pointer to store the received SPI character */ bool adp_interface_read_response(uint8_t* rx_buf, uint16_t length) { bool status; /* Send SPI start condition */ adp_interface_send_start(); status = spi_read_buffer_wait(&edbg_spi, rx_buf, length, 0xFF); /* Send SPI end condition */ adp_interface_send_stop(); return status; }
/** * \brief Function for fetching length of file to be programmed * * Master initially transmits 4 bytes - which is the length of the * the data to be programmed to the device. */ static uint32_t get_length(void) { uint8_t read_buffer[4]; uint32_t len = 0; /* Read 4 bytes of data from master */ while (spi_read_buffer_wait(&slave, read_buffer, 4, dummy) != STATUS_OK); MSB0W(len) = read_buffer[0]; MSB1W(len) = read_buffer[1]; MSB2W(len) = read_buffer[2]; MSB3W(len) = read_buffer[3]; return len; }
/** * \brief Read internal fifo buffer. * * \param buf the buffer to store the data from the fifo buffer. * \param len the amount of data to read. */ void ksz8851_fifo_read(uint8_t *buf, uint32_t len) { uint8_t tmpbuf[9]; spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, true); tmpbuf[0] = FIFO_READ; /* Perform SPI transfer. */ spi_transceive_buffer_wait(&ksz8851snl_master, tmpbuf, tmpbuf, 9); spi_read_buffer_wait(&ksz8851snl_master, buf, len, 0xff); /* Read CRC (don't care). */ spi_read_buffer_wait(&ksz8851snl_master, tmpbuf, 4, 0xff); len += 4; /* Keep internal memory alignment. */ len &= 3; if (len) { spi_read_buffer_wait(&ksz8851snl_master, tmpbuf, len, 0xff); } spi_select_slave(&ksz8851snl_master, &ksz8851snl_slave, false); }
enum ab1815_status ab1815_read(struct ab1815_t *clock, uint8_t offset, uint8_t *buf, uint8_t length) { uint8_t address = AB1815_SPI_READ(offset); enum ab1815_status ret_code = ab1815_status_ERROR; spi_select_slave(clock->spi_bus, clock->slave, true); if(spi_write_buffer_wait(clock->spi_bus, &address, 1) == STATUS_OK) { if(spi_read_buffer_wait(clock->spi_bus, buf, length, SPI_DUMMY) == STATUS_OK) { ret_code = ab1815_status_OK; } } spi_select_slave(clock->spi_bus, clock->slave, false); return ret_code; };
/** * \internal * \brief Test: Sends data at different baud rates. * * This test sends (writes) a byte to the slave and receives the data * at different baudrate testing up to the maximum allowed level. * * Transmission and reception are carried out by polling. * * \param test Current test case. */ static void run_baud_test(const struct test_case *test) { uint32_t test_baud = 1000000; uint8_t txd_data = 0x55; uint8_t rxd_data = 0; bool max_baud = true; /* Skip test if initialization failed */ test_assert_true(test, spi_init_success, "Skipping test due to failed initialization"); /* Structure for SPI configuration */ struct spi_config config; /* Configure the SPI master */ spi_get_config_defaults(&config); config.mux_setting = CONF_SPI_MASTER_SPI_MUX; config.pinmux_pad0 = CONF_SPI_MASTER_DATA_IN_PIN_MUX; config.pinmux_pad1 = PINMUX_UNUSED; config.pinmux_pad2 = CONF_SPI_MASTER_DATA_OUT_PIN_MUX; config.pinmux_pad3 = CONF_SPI_MASTER_SCK_PIN_MUX; do { spi_disable(&master); config.mode_specific.master.baudrate = test_baud; spi_init(&master, CONF_SPI_MASTER_MODULE, &config); spi_enable(&master); /* Send data to slave */ spi_select_slave(&master, &slave_inst, true); spi_write_buffer_wait(&master, &txd_data, 1); spi_read_buffer_wait(&slave, &rxd_data, 1, 0); spi_select_slave(&master, &slave_inst, false); if (txd_data != rxd_data) { max_baud = false; break; } test_baud += 1000000; } while (test_baud <= 24000000); /* Output the result */ test_assert_true(test, max_baud, "Test failed at baudrate: %lu", test_baud); }
int cph_deca_spi_read(uint16_t headerLength, const uint8_t *headerBuffer, uint32_t readlength, uint8_t *readBuffer) { status_code_t result = STATUS_OK; cph_deca_spi_ss_select(); if ((result = spi_write_buffer_wait(&spi_master_instance, headerBuffer, headerLength)) == STATUS_OK) { result = spi_read_buffer_wait(&spi_master_instance, readBuffer, readlength, 0xff); } cph_deca_spi_ss_deselect(); if (result != STATUS_OK) { printf("readfromspi_serial timeout\r\n"); } return result; }
/** * \brief Sends the correct TOKEN on the line to start a read block transfer * * \return true if success, otherwise false * with a update of \ref sd_mmc_spi_err. */ static bool sd_mmc_spi_start_read_block(void) { uint32_t i; uint8_t token; uint16_t dummy = 0xFF; Assert(!(sd_mmc_spi_transfert_pos % sd_mmc_spi_block_size)); /* Wait for start data token: * The read timeout is the Nac timing. * Nac must be computed trough CSD values, * or it is 100ms for SDHC / SDXC * Compute the maximum timeout: * Frequency maximum = 25MHz * 1 byte = 8 cycles * 100ms = 312500 x spi_read_buffer_wait() maximum */ token = 0; i = 500000; do { if (i-- == 0) { sd_mmc_spi_err = SD_MMC_SPI_ERR_READ_TIMEOUT; sd_mmc_spi_debug("%s: Read blocks timeout\n\r", __func__); return false; } spi_read_buffer_wait(&sd_mmc_master, &token, 1, dummy); if (SPI_TOKEN_DATA_ERROR_VALID(token)) { Assert(SPI_TOKEN_DATA_ERROR_ERRORS & token); if (token & (SPI_TOKEN_DATA_ERROR_ERROR | SPI_TOKEN_DATA_ERROR_ECC_ERROR | SPI_TOKEN_DATA_ERROR_CC_ERROR)) { sd_mmc_spi_debug("%s: CRC data error token\n\r", __func__); sd_mmc_spi_err = SD_MMC_SPI_ERR_READ_CRC; } else { sd_mmc_spi_debug("%s: Out of range data error token\n\r", __func__); sd_mmc_spi_err = SD_MMC_SPI_ERR_OUT_OF_RANGE; } return false; } } while (token != SPI_TOKEN_SINGLE_MULTI_READ); return true; }
bool sd_mmc_spi_start_read_blocks(void *dest, uint16_t nb_block) { uint32_t pos; uint16_t dummy = 0xFF; sd_mmc_spi_err = SD_MMC_SPI_NO_ERR; pos = 0; while (nb_block--) { Assert(sd_mmc_spi_nb_block > (sd_mmc_spi_transfert_pos / sd_mmc_spi_block_size)); if (!sd_mmc_spi_start_read_block()) { return false; } // Read block spi_read_buffer_wait(&sd_mmc_master, &((uint8_t*)dest)[pos], sd_mmc_spi_block_size, dummy); pos += sd_mmc_spi_block_size; sd_mmc_spi_transfert_pos += sd_mmc_spi_block_size; sd_mmc_spi_stop_read_block(); } return true; }
/* * @brief spi_isr SPI isr call back handler * * @param return kick_scheduler_t * */ kick_scheduler_t spi_isr(void) { #ifdef SPI_IN_INTERRUPT_MODE /* save the byte just received in the RX buffer */ switch (spi_vars.returnType) { case SPI_FIRSTBYTE: if (spi_vars.numTxedBytes==0) { spi_read_buffer_wait(&master, spi_vars.pNextRxByte, 1, 0); } break; case SPI_BUFFER: spi_read_buffer_wait(&master, spi_vars.pNextRxByte, 1, 0); spi_vars.pNextRxByte++; break; case SPI_LASTBYTE: spi_read_buffer_wait(&master, spi_vars.pNextRxByte, 1, 0); break; } /* one byte less to go */ spi_vars.pNextTxByte++; spi_vars.numTxedBytes++; spi_vars.txBytesLeft--; if (spi_vars.txBytesLeft>0) { /* write next byte to TX buffer */ spi_write_buffer_wait(&master, spi_vars.pNextTxByte, 1); } else { /* put CS signal high to signal end of transmission to slave */ if (spi_vars.isLast==SPI_LAST) { /* Stop the SPI transaction by setting SEL high */ spi_select_slave(&master, &slave, false); } /* SPI is not busy anymore */ spi_vars.busy = 0; /* SPI is done! */ if (spi_vars.callback!=NULL) { /* call the callback */ spi_vars.callback(); /* kick the OS */ return KICK_SCHEDULER; } } return DO_NOT_KICK_SCHEDULER; #else /* this should never happen! */ while(1); /* we can not print from within the BSP. Instead we blink the error LED */ leds_error_blink(); /* reset the board */ board_reset(); /* execution will not reach here, statement to make compiler happy */ return DO_NOT_KICK_SCHEDULER; #endif }
bool sd_mmc_spi_adtc_start(sdmmc_cmd_def_t cmd, uint32_t arg, uint16_t block_size, uint16_t nb_block, bool access_block) { uint8_t dummy = 0xFF; uint8_t cmd_token[6]; uint8_t ncr_timeout; uint8_t r1; //! R1 response uint16_t dummy2 = 0xFF; UNUSED(access_block); Assert(cmd & SDMMC_RESP_PRESENT); // Always a response in SPI mode sd_mmc_spi_err = SD_MMC_SPI_NO_ERR; // Encode SPI command cmd_token[0] = SPI_CMD_ENCODE(SDMMC_CMD_GET_INDEX(cmd)); cmd_token[1] = arg >> 24; cmd_token[2] = arg >> 16; cmd_token[3] = arg >> 8; cmd_token[4] = arg; cmd_token[5] = sd_mmc_spi_crc7(cmd_token, 5); // 8 cycles to respect Ncs timing // Note: This byte does not include start bit "0", // thus it is ignored by card. spi_write_buffer_wait(&sd_mmc_master, &dummy, 1); // Send command spi_write_buffer_wait(&sd_mmc_master, cmd_token, sizeof(cmd_token)); // Wait for response // Two retry will be done to manage the Ncr timing between command and reponse // Ncr: Min. 1x8 clock cycle, Max. 8x8 clock cycles // WORKAROUND for no compliance card (Atmel Internal ref. SD13): r1 = 0xFF; // Ignore first byte because Ncr min. = 8 clock cylces spi_read_buffer_wait(&sd_mmc_master, &r1, 1, dummy2); ncr_timeout = 7; while (1) { spi_read_buffer_wait(&sd_mmc_master, &r1, 1, dummy2); // 8 cycles if ((r1 & R1_SPI_ERROR) == 0) { // Valid R1 response break; } if (--ncr_timeout == 0) { // Here Valid R1 response received sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lX, R1 timeout\n\r", __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg); sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_TIMEOUT; return false; } } // Save R1 (Specific to SPI interface) in 32 bit response // The R1_SPI_IDLE bit can be checked by high level sd_mmc_spi_response_32 = r1; // Manage error in R1 if (r1 & R1_SPI_COM_CRC) { sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%02x, R1_SPI_COM_CRC\n\r", __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1); sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_CRC; return false; } if (r1 & R1_SPI_ILLEGAL_COMMAND) { sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%x, R1 ILLEGAL_COMMAND\n\r", __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1); sd_mmc_spi_err = SD_MMC_SPI_ERR_ILLEGAL_COMMAND; return false; } if (r1 & ~R1_SPI_IDLE) { // Other error sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, r1 0x%x, R1 error\n\r", __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg, r1); sd_mmc_spi_err = SD_MMC_SPI_ERR; return false; } // Manage other responses if (cmd & SDMMC_RESP_BUSY) { if (!sd_mmc_spi_wait_busy()) { sd_mmc_spi_err = SD_MMC_SPI_ERR_RESP_BUSY_TIMEOUT; sd_mmc_spi_debug("%s: cmd %02d, arg 0x%08lx, Busy signal always high\n\r", __func__, (int)SDMMC_CMD_GET_INDEX(cmd), arg); return false; } } if (cmd & SDMMC_RESP_8) { sd_mmc_spi_response_32 = 0; spi_read_buffer_wait(&sd_mmc_master, (uint8_t *)&sd_mmc_spi_response_32, 1, dummy2); sd_mmc_spi_response_32 = le32_to_cpu(sd_mmc_spi_response_32); } if (cmd & SDMMC_RESP_32) { spi_read_buffer_wait(&sd_mmc_master, (uint8_t *)&sd_mmc_spi_response_32, 4, dummy2); sd_mmc_spi_response_32 = be32_to_cpu(sd_mmc_spi_response_32); } sd_mmc_spi_block_size = block_size; sd_mmc_spi_nb_block = nb_block; sd_mmc_spi_transfert_pos = 0; return true; // Command complete }
/*============================================================================== hal_spiRead() =============================================================================*/ uint8_t hal_spiRead(uint8_t * p_reg, uint16_t i_length) { spi_read_buffer_wait(&st_masterInst,p_reg,i_length,0); return *p_reg; } /* hal_spiRead() */
/** * \brief Function for fetching data to be programmed * * This function will read \ref len number of bytes from master for * programming the device. * * \param buffer pointer to the buffer to store data from SPI master * \param len length of the data that will be sent by SPI master */ static void fetch_data(uint8_t *buffer, uint16_t len) { /* Read \ref len number of bytes from master */ while (spi_read_buffer_wait(&slave, buffer, len, dummy) != STATUS_OK); }