OSStatus host_platform_spi_transfer( bus_transfer_direction_t dir, uint8_t* buffer, uint16_t buffer_length ) { OSStatus result; pdc_packet_t pdc_spi_packet = { (uint32_t)buffer, buffer_length }; Pdc* spi_pdc = spi_get_pdc_base( wifi_spi.port ); platform_mcu_powersave_disable(); platform_gpio_output_low( &wifi_spi_pins[WIFI_PIN_SPI_CS] ); pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL); if ( dir == BUS_READ ) { pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL); spi_enable_interrupt(wifi_spi.port, SPI_IER_RXBUFF ); pdc_enable_transfer( spi_pdc, PERIPH_PTCR_TXTEN | PERIPH_PTCR_RXTEN ); } if ( dir == BUS_WRITE ) { spi_enable_interrupt( wifi_spi.port, SPI_IER_ENDTX ); pdc_enable_transfer( spi_pdc, PERIPH_PTCR_TXTEN ); } result = mico_rtos_get_semaphore( &spi_transfer_finished_semaphore, 100 ); platform_gpio_output_high( &wifi_spi_pins[WIFI_PIN_SPI_CS] ); platform_mcu_powersave_enable(); return result; }
/** * \brief Initialize SPI as slave. */ static void spi_slave_initialize(void) { uint32_t i; /* Reset status */ gs_spi_status.ul_total_block_number = 0; gs_spi_status.ul_total_command_number = 0; for (i = 0; i < NB_STATUS_CMD; i++) { gs_spi_status.ul_cmd_list[i] = 0; } gs_ul_spi_state = SLAVE_STATE_IDLE; gs_ul_spi_cmd = RC_SYN; puts("-I- Initialize SPI as slave \r"); /* Configure an SPI peripheral. */ spi_enable_clock(SPI_SLAVE_BASE); spi_disable(SPI_SLAVE_BASE); spi_reset(SPI_SLAVE_BASE); spi_set_slave_mode(SPI_SLAVE_BASE); spi_disable_mode_fault_detect(SPI_SLAVE_BASE); spi_set_peripheral_chip_select_value(SPI_SLAVE_BASE, SPI_CHIP_SEL); spi_set_clock_polarity(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CLK_POLARITY); spi_set_clock_phase(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CLK_PHASE); spi_set_bits_per_transfer(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CSR_BITS_8_BIT); spi_enable_interrupt(SPI_SLAVE_BASE, SPI_IER_RDRF); spi_enable(SPI_SLAVE_BASE); /* Start waiting command. */ spi_slave_transfer(&gs_ul_spi_cmd, sizeof(gs_ul_spi_cmd)); }
/** * \brief Write internal fifo buffer. * * \param buf the buffer to send to the fifo buffer. * \param tot_len the total amount of data to write. * \param len the size of the first pbuf to write from the pbuf chain. */ void ksz8851_fifo_write(uint8_t *buf, uint32_t tot_len, uint32_t len) { static uint8_t frameID = 0; pdc_packet_t g_pdc_spi_tx_packet; pdc_packet_t g_pdc_spi_rx_packet; pdc_packet_t g_pdc_spi_tx_npacket; pdc_packet_t g_pdc_spi_rx_npacket; /* Prepare control word and byte count. */ tmpbuf[0] = FIFO_WRITE; tmpbuf[1] = frameID++ & 0x3f; tmpbuf[2] = 0; tmpbuf[3] = tot_len & 0xff; tmpbuf[4] = tot_len >> 8; /* Prepare PDC transfer. */ g_pdc_spi_tx_packet.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_tx_packet.ul_size = 5; g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_rx_packet.ul_size = 5; g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_tx_npacket.ul_size = len; g_pdc_spi_rx_npacket.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_rx_npacket.ul_size = len; pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_ENDRX); }
/** * \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) { pdc_packet_t g_pdc_spi_tx_packet; pdc_packet_t g_pdc_spi_rx_packet; pdc_packet_t g_pdc_spi_tx_npacket; pdc_packet_t g_pdc_spi_rx_npacket; tmpbuf[0] = FIFO_READ; /* Prepare PDC transfer. */ g_pdc_spi_tx_packet.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_tx_packet.ul_size = 9; g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_rx_packet.ul_size = 9; g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_tx_npacket.ul_size = len; g_pdc_spi_rx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_rx_npacket.ul_size = len; pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_RXBUFF); }
/*! \brief Initialize the SPI in slave mode and enable the spi interrupt. */ static void spi_slave_init(volatile void *spi, uint8_t mode) { /* Enable Clock for SPI module */ sysclk_enable_module(POWER_RED_REG0, PRSPI_bm); /* Configure SPI pins for slave */ /* Set MISO as output high, and set MOSI, SS , SCK as input */ gpio_configure_pin(SPI_SCK, IOPORT_DIR_INPUT); gpio_configure_pin(SPI_MOSI, IOPORT_DIR_INPUT); gpio_configure_pin(SPI_SS, IOPORT_DIR_INPUT); gpio_configure_pin(SPI_MISO, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); /* Set the clock mode */ spi_set_clock_mode(spi, mode); /* Enable SPI as slave */ spi_enable_slave_mode(spi); /* Set the interrupt call back */ spi_set_interrupt_callback(spi_interrupt_callback); /* Enable SPI interrupt */ spi_enable_interrupt(spi); }
/** * \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) { pdc_packet_t g_pdc_spi_tx_packet; pdc_packet_t g_pdc_spi_rx_packet; pdc_packet_t g_pdc_spi_tx_npacket; pdc_packet_t g_pdc_spi_rx_npacket; memset( cmdBuf.uc, '\0', sizeof cmdBuf ); cmdBuf.uc[0] = FIFO_READ; spi_clear_ovres(); /* Prepare PDC transfer. */ g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; g_pdc_spi_tx_packet.ul_size = 9; g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc; g_pdc_spi_rx_packet.ul_size = 9; g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_tx_npacket.ul_size = len; g_pdc_spi_rx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_rx_npacket.ul_size = len; pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_RXBUFF | SPI_IER_OVRES); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); }
/** @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; }
/** * \brief Write internal fifo buffer. * * \param buf the buffer to send to the fifo buffer. * \param ulActualLength the total amount of data to write. * \param ulFIFOLength the size of the first pbuf to write from the pbuf chain. */ void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength) { static uint8_t frameID = 0; pdc_packet_t g_pdc_spi_tx_packet; pdc_packet_t g_pdc_spi_rx_packet; pdc_packet_t g_pdc_spi_tx_npacket; pdc_packet_t g_pdc_spi_rx_npacket; /* Prepare control word and byte count. */ cmdBuf.uc[0] = FIFO_WRITE; cmdBuf.uc[1] = frameID++ & 0x3f; cmdBuf.uc[2] = 0; cmdBuf.uc[3] = ulActualLength & 0xff; cmdBuf.uc[4] = ulActualLength >> 8; spi_clear_ovres(); /* Prepare PDC transfer. */ g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; g_pdc_spi_tx_packet.ul_size = 5; g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc; g_pdc_spi_rx_packet.ul_size = 5; g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; g_pdc_spi_tx_npacket.ul_size = ulFIFOLength; g_pdc_spi_rx_npacket.ul_addr = (uint32_t) tmpbuf; g_pdc_spi_rx_npacket.ul_size = ulFIFOLength; pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); #if( TX_USES_RECV == 1 ) pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_ENDRX | SPI_IER_OVRES); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); #else spi_enable_interrupt(KSZ8851SNL_SPI, SPI_SR_TXBUFE | SPI_IER_OVRES); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_TXTEN); #endif }
static void _spi_init_base(Spi * spi_base) { spi_enable_clock(spi_base); spi_disable(spi_base); spi_reset(spi_base); spi_set_lastxfer(spi_base); spi_set_master_mode(spi_base); spi_disable_mode_fault_detect(spi_base); spi_set_variable_peripheral_select(spi_base); spi_enable_interrupt(_spi_base, SPI_IER_RDRF); // spi_enable_loopback(spi_base); // ?????????????????? }
void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t handler, uint32_t event, DMAUsage hint) { uint32_t pdcenable=0; if(tx){ pdc_packet_t pdc_packet_tx; pdc_packet_tx.ul_addr=(uint32_t)tx; pdc_packet_tx.ul_size=tx_length; pdcenable|=PERIPH_PTCR_TXTEN; /* Configure PDC for data send */ pdc_tx_init(obj->spi.pdc, &pdc_packet_tx, NULL); } if(rx){ pdc_rx_clear_cnt(obj->spi.pdc); pdc_packet_t pdc_packet_rx; pdc_packet_rx.ul_addr=(uint32_t)rx; pdc_packet_rx.ul_size=rx_length; pdcenable|=PERIPH_PTCR_RXTEN; /* Configure PDC for data receive */ pdc_rx_init(obj->spi.pdc, &pdc_packet_rx, NULL); } obj->spi.dma_usage=hint; obj->spi.event=event; gCallbackHandler[obj->spi.module_number]=handler; NVIC_ClearPendingIRQ(obj->spi.irq_type); /* Enable SPI interrupt */ NVIC_EnableIRQ(obj->spi.irq_type); /* Enable SPI IRQ */ spi_enable_interrupt(obj->spi.spi_base, SPI_IER_RXBUFF| SPI_IER_TXBUFE | SPI_IER_MODF | SPI_IER_OVRES); /* Enable PDC transfers */ pdc_enable_transfer(obj->spi.pdc, pdcenable ); }
/* * Initialise the SPI interface as a SLAVE * */ void spi_slave_initialize(void) { NVIC_DisableIRQ(SPI_IRQn); NVIC_ClearPendingIRQ(SPI_IRQn); NVIC_SetPriority(SPI_IRQn, 0); NVIC_EnableIRQ(SPI_IRQn); /* Configure an SPI peripheral. */ spi_enable_clock(SPI_SLAVE_BASE); spi_disable(SPI_SLAVE_BASE); spi_reset(SPI_SLAVE_BASE); spi_set_slave_mode(SPI_SLAVE_BASE); spi_disable_mode_fault_detect(SPI_SLAVE_BASE); spi_set_peripheral_chip_select_value(SPI_SLAVE_BASE, SPI_CHIP_PCS); spi_set_clock_polarity(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CLK_POLARITY); spi_set_clock_phase(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CLK_PHASE); spi_set_bits_per_transfer(SPI_SLAVE_BASE, SPI_CHIP_SEL, SPI_CSR_BITS_8_BIT); spi_enable_interrupt(SPI_SLAVE_BASE, SPI_IER_RDRF); spi_enable(SPI_SLAVE_BASE); }
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; }
/** * \ingroup freertos_spi_peripheral_control_group * \brief Initiate a completely asynchronous multi-byte write operation on an * SPI peripheral. * * freertos_spi_write_packet_async() is an ASF specific FreeRTOS driver function. * It configures the SPI peripheral DMA controller (PDC) to transmit data on the * SPI port, then returns. freertos_spi_write_packet_async() does not wait for * the transmission to complete before returning. * * The FreeRTOS SPI driver is initialized using a call to * freertos_spi_master_init(). The freertos_driver_parameters.options_flags * parameter passed into the initialization function defines the driver behavior. * freertos_spi_write_packet_async() can only be used if the * freertos_driver_parameters.options_flags parameter passed to the initialization * function had the WAIT_TX_COMPLETE bit clear. * * freertos_spi_write_packet_async() is an advanced function and readers are * recommended to also reference the application note and examples that * accompany the FreeRTOS ASF drivers. freertos_spi_write_packet() is a version * that does not exit until the PDC transfer is complete, but still allows other * RTOS tasks to execute while the transmission is in progress. * * The FreeRTOS ASF driver both installs and handles the SPI PDC interrupts. * Users do not need to concern themselves with interrupt handling, and must * not install their own interrupt handler. * * \param p_spi The handle to the SPI peripheral returned by the * freertos_spi_master_init() call used to initialise the peripheral. * \param data A pointer to the data to be transmitted. * \param len The number of bytes to transmit. * \param block_time_ticks The FreeRTOS ASF SPI driver is initialized using a * call to freertos_spi_master_init(). The * freertos_driver_parameters.options_flags parameter passed to the * initialization function defines the driver behavior. If * freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit * set, then the driver will only write to the SPI peripheral if it has * first gained exclusive access to it. block_time_ticks specifies the * maximum amount of time the driver will wait to get exclusive access * before aborting the write operation. Other tasks will execute during any * waiting time. block_time_ticks is specified in RTOS tick periods. To * specify a block time in milliseconds, divide the milliseconds value by * portTICK_RATE_MS, and pass the result in block_time_ticks. * portTICK_RATE_MS is defined by FreeRTOS. * \param notification_semaphore The RTOS task that calls the transmit * function exits the transmit function as soon as the transmission starts. * The data being transmitted by the PDC must not be modified until after * the transmission has completed. The PDC interrupt (handled internally by * the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer * completes. The notification_semaphore therefore provides a mechanism for * the calling task to know when the PDC has finished accessing the data. * The calling task can call standard FreeRTOS functions to block on the * semaphore until the PDC interrupt occurs. Other RTOS tasks will execute * while the the calling task is in the Blocked state. The semaphore must * be created using the FreeRTOS vSemaphoreCreateBinary() API function * before it is used as a parameter. * * \return ERR_INVALID_ARG is returned if an input parameter is invalid. * ERR_TIMEOUT is returned if block_time_ticks passed before exclusive * access to the SPI peripheral could be obtained. STATUS_OK is returned if * the PDC was successfully configured to perform the SPI write operation. */ status_code_t freertos_spi_write_packet_async(freertos_spi_if p_spi, const uint8_t *data, size_t len, portTickType block_time_ticks, xSemaphoreHandle notification_semaphore) { status_code_t return_value; portBASE_TYPE spi_index; Spi *spi_base; spi_base = (Spi *) p_spi; spi_index = get_pdc_peripheral_details(all_spi_definitions, MAX_SPIS, (void *) spi_base); /* Don't do anything unless a valid SPI pointer was used. */ if (spi_index < MAX_SPIS) { return_value = freertos_obtain_peripheral_access_mutex( &(tx_dma_control[spi_index]), &block_time_ticks); if (return_value == STATUS_OK) { freertos_start_pdc_tx(&(tx_dma_control[spi_index]), data, len, all_spi_definitions[spi_index].pdc_base_address, notification_semaphore); /* Catch the end of transmission so the access mutex can be returned, and the task notified (if it supplied a notification semaphore). The interrupt can be enabled here because the ENDTX signal from the PDC to the peripheral will have been de-asserted when the next transfer was configured. */ spi_enable_interrupt(spi_base, SPI_IER_ENDTX); return_value = freertos_optionally_wait_transfer_completion( &(tx_dma_control[spi_index]), notification_semaphore, block_time_ticks); } } else { return_value = ERR_INVALID_ARG; } return return_value; }
/** * \brief Set SPI slave transfer. * * \param p_buf Pointer to buffer to transfer. * \param size Size of the buffer. */ static void spi_slave_transfer(void *p_tbuf, uint32_t tsize, void *p_rbuf, uint32_t rsize) { uint32_t spi_ier; pdc_packet_t pdc_spi_packet; pdc_spi_packet.ul_addr = (uint32_t)p_rbuf; pdc_spi_packet.ul_size = rsize; pdc_rx_init(g_p_spis_pdc, &pdc_spi_packet, NULL); pdc_spi_packet.ul_addr = (uint32_t)p_tbuf; pdc_spi_packet.ul_size = tsize; pdc_tx_init(g_p_spis_pdc, &pdc_spi_packet, NULL); /* Enable the RX and TX PDC transfer requests */ pdc_enable_transfer(g_p_spis_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); /* Transfer done handler is in ISR */ spi_ier = SPI_IER_NSSR | SPI_IER_RXBUFF; spi_enable_interrupt(SPI_SLAVE_BASE, spi_ier) ; }
OSStatus host_platform_spi_transfer( bus_transfer_direction_t dir, uint8_t* buffer, uint16_t buffer_length ) { OSStatus result; uint8_t *junk; MCU_CLOCKS_NEEDED(); #ifdef USE_OWN_SPI_DRV pdc_packet_t pdc_spi_packet; pdc_spi_packet.ul_addr = (uint32_t)buffer; pdc_spi_packet.ul_size = buffer_length; pdc_tx_init(spi_m_pdc, &pdc_spi_packet, NULL); if ( dir == BUS_READ ) { pdc_spi_packet.ul_addr = (uint32_t)buffer; pdc_spi_packet.ul_size = buffer_length; } if ( dir == BUS_WRITE ) { junk = malloc(buffer_length); pdc_spi_packet.ul_addr = (uint32_t)junk; pdc_spi_packet.ul_size = buffer_length; } pdc_rx_init(spi_m_pdc, &pdc_spi_packet, NULL); #if 0 if ( dir == BUS_WRITE ) { spi_enable_interrupt(SPI_MASTER_BASE, SPI_IER_ENDTX); NVIC_EnableIRQ(SPI_IRQn); } else { spi_enable_interrupt(SPI_MASTER_BASE, SPI_IER_ENDRX); NVIC_EnableIRQ(SPI_IRQn); } #endif //platform_log("dir = %d, len = %d",dir, buffer_length);//TBD #ifndef HARD_CS_NSS0 mico_gpio_output_low( MICO_GPIO_15 ); #endif /* Enable the RX and TX PDC transfer requests */ pdc_enable_transfer(spi_m_pdc, PERIPH_PTCR_TXTEN | PERIPH_PTCR_RXTEN);//pdc buffer address increase automatic. //platform_log("pdc status = 0x%x",pdc_read_status(spi_m_pdc)); #ifndef NO_MICO_RTOS result = mico_rtos_get_semaphore( &spi_transfer_finished_semaphore, 100 ); #else /* Waiting transfer done*/ while((spi_read_status(SPI_MASTER_BASE) & SPI_SR_RXBUFF) == 0) { __asm("wfi"); } #endif if ( dir == BUS_WRITE ) { if (junk) free(junk); } /* Disable the RX and TX PDC transfer requests */ pdc_disable_transfer(spi_m_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); #ifndef HARD_CS_NSS0 mico_gpio_output_high( MICO_GPIO_15 ); #endif #if 1 //clear PDC Perph Status flags pdc_spi_packet.ul_addr = NULL; pdc_spi_packet.ul_size = 3; pdc_tx_init(spi_m_pdc, &pdc_spi_packet, NULL); pdc_rx_init(spi_m_pdc, &pdc_spi_packet, NULL); #endif #else //spi_master_vec : tx_dscr[0].data = buffer; tx_dscr[0].length = buffer_length; tx_dscr[1].data = NULL; tx_dscr[1].length = 0; //if ( dir == BUS_READ ) { rx_dscr[0].data = buffer; rx_dscr[0].length = buffer_length; //} else { // rx_dscr[0].data = &junk; // rx_dscr[0].length = 0; //} rx_dscr[1].data = NULL; rx_dscr[1].length = 0; #ifndef HARD_CS_NSS0 mico_gpio_output_low( MICO_GPIO_15 ); #endif if (spi_master_vec_transceive_buffer_wait(&spi_master, tx_dscr, rx_dscr) != STATUS_OK) { platform_log("STATUS = -1"); return kGeneralErr; } #ifndef HARD_CS_NSS0 mico_gpio_output_high( MICO_GPIO_15 ); #endif #endif /* USE_OWN_SPI_DR */ MCU_CLOCKS_NOT_NEEDED(); #ifdef USE_OWN_SPI_DRV return result; #else return 0; #endif }
OSStatus host_platform_bus_init( void ) { #ifndef USE_OWN_SPI_DRV struct spi_master_vec_config spi; #else pdc_packet_t pdc_spi_packet; #endif OSStatus result; MCU_CLOCKS_NEEDED(); spi_disable_interrupt(SPI_MASTER_BASE, 0xffffffff); //Disable_global_interrupt();//TBD! result = mico_rtos_init_semaphore( &spi_transfer_finished_semaphore, 1 ); if ( result != kNoErr ) { return result; } mico_gpio_initialize( (mico_gpio_t)MICO_GPIO_9, INPUT_PULL_UP ); //ioport_port_mask_t ul_mask = ioport_pin_to_mask(CREATE_IOPORT_PIN(PORTA,24)); //pio_set_input(PIOA,ul_mask, PIO_PULLUP|PIO_DEBOUNCE); mico_gpio_enable_IRQ( (mico_gpio_t)MICO_GPIO_9, IRQ_TRIGGER_RISING_EDGE, spi_irq_handler, NULL ); #ifndef HARD_CS_NSS0 mico_gpio_initialize( MICO_GPIO_15, OUTPUT_PUSH_PULL);//spi ss/cs mico_gpio_output_high( MICO_GPIO_15 );//MICO_GPIO_15 TBD! #else ioport_set_pin_peripheral_mode(SPI_NPCS0_GPIO, SPI_NPCS0_FLAGS);//TBD! #endif /* set PORTB 01 to high to put WLAN module into g_SPI mode */ mico_gpio_initialize( (mico_gpio_t)WL_GPIO0, OUTPUT_PUSH_PULL ); mico_gpio_output_high( (mico_gpio_t)WL_GPIO0 ); #ifdef USE_OWN_SPI_DRV #if (SAMG55) /* Enable the peripheral and set SPI mode. */ flexcom_enable(BOARD_FLEXCOM_SPI); flexcom_set_opmode(BOARD_FLEXCOM_SPI, FLEXCOM_SPI); #else /* Configure an SPI peripheral. */ pmc_enable_periph_clk(SPI_ID); #endif //Init pdc, and clear RX TX. spi_m_pdc = spi_get_pdc_base(SPI_MASTER_BASE); pdc_spi_packet.ul_addr = NULL; pdc_spi_packet.ul_size = 3; pdc_tx_init(spi_m_pdc, &pdc_spi_packet, NULL); pdc_rx_init(spi_m_pdc, &pdc_spi_packet, NULL); spi_disable(SPI_MASTER_BASE); spi_reset(SPI_MASTER_BASE); spi_set_lastxfer(SPI_MASTER_BASE); spi_set_master_mode(SPI_MASTER_BASE); spi_disable_mode_fault_detect(SPI_MASTER_BASE); #ifdef HARD_CS_NSS0 //spi_enable_peripheral_select_decode(SPI_MASTER_BASE); //spi_set_peripheral_chip_select_value(SPI_MASTER_BASE, SPI_CHIP_SEL); spi_set_peripheral_chip_select_value(SPI_MASTER_BASE, SPI_CHIP_PCS); //use soft nss comment here #endif spi_set_clock_polarity(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_CLK_POLARITY); spi_set_clock_phase(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_CLK_PHASE); 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, (sysclk_get_cpu_hz() / SPI_BAUD_RATE)); spi_set_transfer_delay(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_DLYBS, SPI_DLYBCT); /* Must be lower priority than the value of configMAX_SYSCALL_INTERRUPT_PRIORITY */ /* otherwise FreeRTOS will not be able to mask the interrupt */ /* keep in mind that ARMCM3 interrupt priority logic is inverted, the highest value */ /* is the lowest priority */ /* Configure SPI interrupts . */ spi_enable_interrupt(SPI_MASTER_BASE, SPI_IER_RXBUFF); //spi_enable_interrupt(SPI_MASTER_BASE, SPI_IER_NSSR | SPI_IER_RXBUFF); NVIC_DisableIRQ(SPI_IRQn); //irq_register_handler(SPI_IRQn, 3); NVIC_ClearPendingIRQ(SPI_IRQn); NVIC_SetPriority(SPI_IRQn, 3); NVIC_EnableIRQ(SPI_IRQn); spi_enable(SPI_MASTER_BASE); #else spi.baudrate = SPI_BAUD_RATE; if (STATUS_OK != spi_master_vec_init(&spi_master, SPI_MASTER_BASE, &spi)) { return -1; } spi_master_vec_enable(&spi_master); #endif //if (!Is_global_interrupt_enabled()) // Enable_global_interrupt(); MCU_CLOCKS_NOT_NEEDED(); return kNoErr; }
/** * \ingroup freertos_spi_peripheral_control_group * \brief Initiate a completely asynchronous multi-byte read operation on an SPI * peripheral. * * freertos_spi_read_packet_async() is an ASF specific FreeRTOS driver function. * It configures the SPI peripheral DMA controller (PDC) to read data from the * SPI port, then returns. freertos_spi_read_packet_async() does not wait for * the reception to complete before returning. * * The FreeRTOS ASF SPI driver is initialized using a call to * freertos_spi_master_init(). The freertos_driver_parameters.options_flags * parameter passed into the initialization function defines the driver behavior. * freertos_spi_read_packet_async() can only be used if the * freertos_driver_parameters.options_flags parameter passed to the initialization * function had the WAIT_RX_COMPLETE bit clear. * * freertos_spi_read_packet_async() is an advanced function and readers are * recommended to also reference the application note and examples that * accompany the FreeRTOS ASF drivers. freertos_spi_read_packet() is a version * that does not exit until the PDC transfer is complete, but still allows other * RTOS tasks to execute while the transmission is in progress. * * The FreeRTOS ASF driver both installs and handles the SPI PDC interrupts. * Users do not need to concern themselves with interrupt handling, and must * not install their own interrupt handler. * * \param p_spi The handle to the SPI port returned by the * freertos_spi_master_init() call used to initialise the port. * \param data A pointer to the buffer into which received data is to be * written. * \param len The number of bytes to receive. * \param block_time_ticks The FreeRTOS ASF SPI driver is initialized using a * call to freertos_spi_master_init(). The * freertos_driver_parameters.options_flags parameter passed to the * initialization function defines the driver behavior. If * freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit * set, then the driver will only read from the SPI peripheral if it has * first gained exclusive access to it. block_time_ticks specifies the * maximum amount of time the driver will wait to get exclusive access * before aborting the read operation. Other tasks will execute during any * waiting time. block_time_ticks is specified in RTOS tick periods. To * specify a block time in milliseconds, divide the milliseconds value by * portTICK_RATE_MS, and pass the result in block_time_ticks. * portTICK_RATE_MS is defined by FreeRTOS. * \param notification_semaphore The RTOS task that calls the receive * function exits the receive function as soon as the reception starts. * The data being received by the PDC cannot normally be processed until * after the reception has completed. The PDC interrupt (handled internally * by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer * completes. The notification_semaphore therefore provides a mechanism for * the calling task to know when the PDC has read the requested number of * bytes. The calling task can call standard FreeRTOS functions to block on * the semaphore until the PDC interrupt occurs. Other RTOS tasks will * execute while the the calling task is in the Blocked state. The * semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API * function before it is used as a parameter. * * \return ERR_INVALID_ARG is returned if an input parameter is invalid. * ERR_TIMEOUT is returned if block_time_ticks passed before exclusive * access to the SPI peripheral could be obtained. STATUS_OK is returned if * the PDC was successfully configured to perform the SPI read operation. */ status_code_t freertos_spi_read_packet_async(freertos_spi_if p_spi, uint8_t *data, uint32_t len, portTickType block_time_ticks, xSemaphoreHandle notification_semaphore) { status_code_t return_value; pdc_packet_t pdc_tx_packet; portBASE_TYPE spi_index; Spi *spi_base; volatile uint16_t junk_value; spi_base = (Spi *) p_spi; spi_index = get_pdc_peripheral_details(all_spi_definitions, MAX_SPIS, (void *) spi_base); /* Don't do anything unless a valid SPI pointer was used. */ if (spi_index < MAX_SPIS) { /* Because the peripheral is half duplex, there is only one access mutex and the rx uses the tx mutex. */ return_value = freertos_obtain_peripheral_access_mutex( &(tx_dma_control[spi_index]), &block_time_ticks); if (return_value == STATUS_OK) { /* Data must be sent for data to be received. Set the receive buffer to all 0xffs so it can also be used as the send buffer. */ memset((void *)data, 0xff, (size_t)len); /* Ensure Rx is already empty. */ while(spi_is_rx_full(all_spi_definitions[spi_index].peripheral_base_address) != 0) { junk_value = ((Spi*) all_spi_definitions[spi_index].peripheral_base_address)->SPI_RDR; (void) junk_value; } /* Start the PDC reception, although nothing is received until the SPI is also transmitting. */ freertos_start_pdc_rx(&(rx_dma_control[spi_index]), data, len, all_spi_definitions[spi_index].pdc_base_address, notification_semaphore); /* Start the transmit so data is also received. */ pdc_tx_packet.ul_addr = (uint32_t)data; pdc_tx_packet.ul_size = (uint32_t)len; pdc_disable_transfer( all_spi_definitions[spi_index].pdc_base_address, PERIPH_PTCR_TXTDIS); pdc_tx_init( all_spi_definitions[spi_index].pdc_base_address, &pdc_tx_packet, NULL); pdc_enable_transfer( all_spi_definitions[spi_index].pdc_base_address, PERIPH_PTCR_TXTEN); /* Catch the end of reception so the access mutex can be returned, and the task notified (if it supplied a notification semaphore). The interrupt can be enabled here because the ENDRX signal from the PDC to the peripheral will have been de-asserted when the next transfer was configured. */ spi_enable_interrupt(spi_base, SPI_IER_ENDRX); return_value = freertos_optionally_wait_transfer_completion( &(rx_dma_control[spi_index]), notification_semaphore, block_time_ticks); } } else { return_value = ERR_INVALID_ARG; } return return_value; }
/** * \ingroup freertos_spi_peripheral_control_group * \brief Initializes the FreeRTOS ASF SPI master driver for the specified SPI port. * * freertos_spi_master_init() is an ASF specific FreeRTOS driver function. It * must be called before any other ASF specific FreeRTOS driver functions * attempt to access the same SPI port. * * If freertos_driver_parameters->operation_mode equals SPI_MASTER then * freertos_spi_master_init() will configure the SPI port for master mode * operation and enable the peripheral. If * freertos_driver_parameters->operation_mode equals any other value then * freertos_spi_master_init() will not take any action. * * Other ASF SPI functions, such as those to set the SPI clock rate and other * bus parameters, can be called after freertos_spi_master_init() has completed * successfully. * * The FreeRTOS ASF driver both installs and handles the SPI PDC interrupts. * Users do not need to concern themselves with interrupt handling, and must * not install their own interrupt handler. * * This driver is provided with an application note, and an example project that * demonstrates the use of this function. * * \param p_spi The SPI peripheral being initialized. * \param freertos_driver_parameters Defines the driver behavior. See the * freertos_peripheral_options_t documentation, and the application note that * accompanies the ASF specific FreeRTOS functions. * * \return If the initialization completes successfully then a handle that can * be used with FreeRTOS SPI read and write functions is returned. If * the initialisation fails then NULL is returned. */ freertos_spi_if freertos_spi_master_init(Spi *p_spi, const freertos_peripheral_options_t *const freertos_driver_parameters) { portBASE_TYPE spi_index; bool is_valid_operating_mode; freertos_spi_if return_value; const enum peripheral_operation_mode valid_operating_modes[] = {SPI_MASTER}; /* Find the index into the all_spi_definitions array that holds details of the p_spi peripheral. */ spi_index = get_pdc_peripheral_details(all_spi_definitions, MAX_SPIS, (void *) p_spi); /* Check the requested operating mode is valid for the peripheral. */ is_valid_operating_mode = check_requested_operating_mode( freertos_driver_parameters->operation_mode, valid_operating_modes, sizeof(valid_operating_modes) / sizeof(enum peripheral_operation_mode)); /* Don't do anything unless a valid p_spi pointer was used, and a valid operating mode was requested. */ if ((spi_index < MAX_SPIS) && (is_valid_operating_mode == true)) { /* This function must be called exactly once per supported spi. Check it has not been called before. */ configASSERT(memcmp((void *) &(tx_dma_control[spi_index]), &null_dma_control, sizeof(null_dma_control)) == 0); configASSERT(memcmp((void *) &(rx_dma_control[spi_index]), &null_dma_control, sizeof(null_dma_control)) == 0); /* Ensure everything is disabled before configuration. */ spi_disable(all_spi_definitions[spi_index].peripheral_base_address); pdc_disable_transfer( all_spi_definitions[spi_index].pdc_base_address, (PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS)); spi_disable_interrupt( all_spi_definitions[spi_index].peripheral_base_address, MASK_ALL_INTERRUPTS); switch (freertos_driver_parameters->operation_mode) { case SPI_MASTER: /* Call the standard ASF init function. */ spi_master_init( all_spi_definitions[spi_index].peripheral_base_address); break; default: /* No other modes are currently supported. */ break; } /* Create any required peripheral access mutexes and transaction complete semaphores. This peripheral is half duplex so only a single access mutex is required. */ create_peripheral_control_semaphores( freertos_driver_parameters->options_flags, &(tx_dma_control[spi_index]), &(rx_dma_control[spi_index])); /* Configure and enable the SPI interrupt in the interrupt controller. */ configure_interrupt_controller( all_spi_definitions[spi_index].peripheral_irq, freertos_driver_parameters->interrupt_priority); /* Error interrupts are always enabled. */ spi_enable_interrupt( all_spi_definitions[spi_index].peripheral_base_address, IER_ERROR_INTERRUPTS); /* Finally, enable the peripheral. */ spi_enable(all_spi_definitions[spi_index].peripheral_base_address); return_value = (freertos_spi_if)p_spi; } else { return_value = NULL; } return return_value; }
/** * \brief Test SPI transfer. * * This test tests SPI read/write. * * \param test Current test case. */ static void run_spi_trans_test(const struct test_case *test) { spi_status_t rc; uint16_t spi_data; uint8_t spi_pcs; spi_reset(CONF_TEST_SPI); spi_set_lastxfer(CONF_TEST_SPI); spi_set_master_mode(CONF_TEST_SPI); spi_disable_mode_fault_detect(CONF_TEST_SPI); spi_set_peripheral_chip_select_value(CONF_TEST_SPI, CONF_TEST_SPI_NPCS); spi_set_clock_polarity(CONF_TEST_SPI, CONF_TEST_SPI_NPCS, SPI_CLK_POLARITY); spi_set_clock_phase(CONF_TEST_SPI, CONF_TEST_SPI_NPCS, SPI_CLK_PHASE); spi_set_bits_per_transfer(CONF_TEST_SPI, CONF_TEST_SPI_NPCS, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(CONF_TEST_SPI, CONF_TEST_SPI_NPCS, (sysclk_get_cpu_hz() / TEST_CLOCK)); spi_set_transfer_delay(CONF_TEST_SPI, CONF_TEST_SPI_NPCS, SPI_DLYBS, SPI_DLYBCT); spi_set_variable_peripheral_select(CONF_TEST_SPI); spi_enable_loopback(CONF_TEST_SPI); /* Test read/write timeout: should return SPI_ERROR_TIMEOUT. */ rc = spi_write(CONF_TEST_SPI, TEST_PATTERN, TEST_PCS, 1); test_assert_true(test, rc == SPI_ERROR_TIMEOUT, "Test SPI Write timeout: return code should not be %d", rc); rc = spi_read(CONF_TEST_SPI, &spi_data, &spi_pcs); test_assert_true(test, rc == SPI_ERROR_TIMEOUT, "Test SPI Read timeout: return code should not be %d", rc); spi_enable(CONF_TEST_SPI); spi_enable_interrupt(CONF_TEST_SPI, SPI_IER_TDRE|SPI_IER_RDRF); NVIC_EnableIRQ((IRQn_Type)CONF_TEST_SPI_ID); /* Test write: should return OK. */ rc = spi_write(CONF_TEST_SPI, TEST_PATTERN, TEST_PCS, 1); test_assert_true(test, rc == SPI_OK, "Test SPI Write: return code should not be %d", rc); /* Test read: should return OK with what is sent. */ rc = spi_read(CONF_TEST_SPI, &spi_data, &spi_pcs); test_assert_true(test, rc == SPI_OK, "Test SPI Read: return code should not be %d", rc); test_assert_true(test, spi_data == TEST_PATTERN, "Unexpected SPI data: %x, should be %x", spi_data, TEST_PATTERN); test_assert_true(test, spi_pcs == TEST_PCS, "Unexpected SPI PCS: %x, should be %x", spi_pcs, TEST_PCS); /* Check interrupts. */ test_assert_true(test, g_b_spi_interrupt_tx_ready, "Test SPI TX interrupt not detected"); test_assert_true(test, g_b_spi_interrupt_rx_ready, "Test SPI RX interrupt not detected"); /* Done, disable SPI and all interrupts. */ spi_disable_loopback(CONF_TEST_SPI); spi_disable(CONF_TEST_SPI); spi_disable_interrupt(CONF_TEST_SPI, 0xFFFFFFFF); NVIC_DisableIRQ((IRQn_Type)CONF_TEST_SPI_ID); }
/* * Configure the SPI hardware, including SPI clock speed, mode, delays, chip select pins * It uses values listed in */ void AJ_WSL_SPI_InitializeSPIController(void) { uint32_t config; /* Initialize and enable DMA controller. */ pmc_enable_periph_clk(ID_DMAC); dmac_init(DMAC); dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN); dmac_enable(DMAC); /* Configure DMA TX channel. */ config = 0; config |= DMAC_CFG_DST_PER(AJ_SPI_TX_INDEX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(DMAC, AJ_DMA_TX_CHANNEL, config); /* Configure DMA RX channel. */ config = 0; config |= DMAC_CFG_SRC_PER(AJ_SPI_RX_INDEX) | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(DMAC, AJ_DMA_RX_CHANNEL, config); /* Enable receive channel interrupt for DMAC. */ uint8_t* interruptEnableAddress = AJ_SPI_ISER1_IEN_ADDR; *interruptEnableAddress = AJ_SPI_DMAC_IEN_BIT; dmac_enable_interrupt(DMAC, (1 << AJ_DMA_RX_CHANNEL)); dmac_enable_interrupt(DMAC, (1 << AJ_DMA_TX_CHANNEL)); //AJ_WSL_DMA_Setup(); dmac_channel_disable(DMAC, AJ_DMA_TX_CHANNEL); dmac_channel_disable(DMAC, AJ_DMA_RX_CHANNEL); /* * Configure the hardware to enable SPI and some output pins */ { pmc_enable_periph_clk(ID_PIOA); pmc_enable_periph_clk(ID_PIOB); pmc_enable_periph_clk(ID_PIOC); pmc_enable_periph_clk(ID_PIOD); // make all of these pins controlled by the right I/O controller pio_configure_pin_group(PIOA, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_A); pio_configure_pin_group(PIOB, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_B); pio_configure_pin_group(PIOC, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_C); pio_configure_pin_group(PIOD, 0xFFFFFFFF, PIO_TYPE_PIO_PERIPH_D); /* * Reset the device by toggling the CHIP_POWER */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_PIN_LEVEL_LOW); AJ_Sleep(10); ioport_set_pin_level(AJ_WSL_SPI_CHIP_POWER_PIN, IOPORT_PIN_LEVEL_HIGH); /* * Reset the device by toggling the CHIP_PWD# signal */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_PIN_LEVEL_LOW); AJ_Sleep(10); ioport_set_pin_level(AJ_WSL_SPI_CHIP_PWD_PIN, IOPORT_PIN_LEVEL_HIGH); /* configure the pin that detects SPI data ready from the target chip */ ioport_set_pin_dir(AJ_WSL_SPI_CHIP_SPI_INT_PIN, IOPORT_DIR_INPUT); ioport_set_pin_sense_mode(AJ_WSL_SPI_CHIP_SPI_INT_PIN, IOPORT_SENSE_LEVEL_LOW); pio_handler_set(PIOC, ID_PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT, (PIO_PULLUP | PIO_IT_FALL_EDGE), &AJ_WSL_SPI_CHIP_SPI_ISR); pio_handler_set_priority(PIOD, (IRQn_Type) ID_PIOC, 0xB); pio_enable_interrupt(PIOC, AJ_WSL_SPI_CHIP_SPI_INT_BIT); } spi_enable_clock(AJ_WSL_SPI_DEVICE); spi_reset(AJ_WSL_SPI_DEVICE); spi_set_lastxfer(AJ_WSL_SPI_DEVICE); spi_set_master_mode(AJ_WSL_SPI_DEVICE); spi_disable_mode_fault_detect(AJ_WSL_SPI_DEVICE); spi_set_peripheral_chip_select_value(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS); spi_set_clock_polarity(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_CLOCK_POLARITY); spi_set_clock_phase(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_CLOCK_PHASE); spi_set_bits_per_transfer(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, (sysclk_get_cpu_hz() / AJ_WSL_SPI_CLOCK_RATE)); spi_set_transfer_delay(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, AJ_WSL_SPI_DELAY_BEFORE_CLOCK, AJ_WSL_SPI_DELAY_BETWEEN_TRANSFERS); spi_set_fixed_peripheral_select(AJ_WSL_SPI_DEVICE); spi_configure_cs_behavior(AJ_WSL_SPI_DEVICE, AJ_WSL_SPI_DEVICE_NPCS, SPI_CS_RISE_FORCED); spi_enable_interrupt(AJ_WSL_SPI_DEVICE, SPI_IER_TDRE | SPI_IER_RDRF); spi_enable(AJ_WSL_SPI_DEVICE); }