Exemplo n.º 1
0
// asynchronous API
void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
{
    struct spi_s *spiobj = SPI_S(obj);
    SPI_HandleTypeDef *handle = &(spiobj->handle);

    // TODO: DMA usage is currently ignored
    (void) hint;

    // check which use-case we have
    bool use_tx = (tx != NULL && tx_length > 0);
    bool use_rx = (rx != NULL && rx_length > 0);
    bool is16bit = (handle->Init.DataSize == SPI_DATASIZE_16BIT);

    // don't do anything, if the buffers aren't valid
    if (!use_tx && !use_rx)
        return;

    // copy the buffers to the SPI object
    obj->tx_buff.buffer = (void *) tx;
    obj->tx_buff.length = tx_length;
    obj->tx_buff.pos = 0;
    obj->tx_buff.width = is16bit ? 16 : 8;

    obj->rx_buff.buffer = rx;
    obj->rx_buff.length = rx_length;
    obj->rx_buff.pos = 0;
    obj->rx_buff.width = obj->tx_buff.width;

    obj->spi.event = event;

    DEBUG_PRINTF("SPI: Transfer: %u, %u\n", tx_length, rx_length);

    // register the thunking handler
    IRQn_Type irq_n = spiobj->spiIRQ;
    NVIC_SetVector(irq_n, (uint32_t)handler);

    // enable the right hal transfer
    if (use_tx && use_rx) {
        // we cannot manage different rx / tx sizes, let's use smaller one
        size_t size = (tx_length < rx_length)? tx_length : rx_length;
        if(tx_length != rx_length) {
            DEBUG_PRINTF("SPI: Full duplex transfer only 1 size: %d\n", size);
            obj->tx_buff.length = size;
            obj->rx_buff.length = size;
        }
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TXRX, tx, rx, size);
    } else if (use_tx) {
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX, tx, NULL, tx_length);
    } else if (use_rx) {
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX, NULL, rx, rx_length);
    }
}
Exemplo n.º 2
0
// asynchronous API
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)
{
    // TODO: DMA usage is currently ignored
    (void) hint;

    // check which use-case we have
    bool use_tx = (tx != NULL && tx_length > 0);
    bool use_rx = (rx != NULL && rx_length > 0);

    // don't do anything, if the buffers aren't valid
    if (!use_tx && !use_rx)
        return;

    SPI_HandleTypeDef *handle = &SpiHandle[obj->spi.module];

    bool is16bit = (handle->Init.DataSize == SPI_DATASIZE_16BIT);

    // copy the buffers to the SPI object
    obj->tx_buff.buffer = tx;
    obj->tx_buff.length = tx_length;
    obj->tx_buff.pos = 0;
    obj->tx_buff.width = is16bit ? 16 : 8;

    obj->rx_buff.buffer = rx;
    obj->rx_buff.length = rx_length;
    obj->rx_buff.pos = 0;
    obj->rx_buff.width = obj->tx_buff.width;

    obj->spi.event = event;

    DEBUG_PRINTF("SPI%u: Transfer: %u, %u\n", obj->spi.module+1, tx_length, rx_length);

    // register the thunking handler
    IRQn_Type irq_n = SpiIRQs[obj->spi.module];
    vIRQ_SetVector(irq_n, handler);

    // enable the right hal transfer
    if (use_tx && use_rx) {
        // transfer with the min(tx, rx), then later either transmit _or_ receive the remainder
        size_t size = (tx_length < rx_length)? tx_length : rx_length;
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TXRX, tx, rx, size);
    } else if (use_tx) {
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX, tx, NULL, tx_length);
    } else if (use_rx) {
        spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX, NULL, rx, rx_length);
    }
}
Exemplo n.º 3
0
uint32_t spi_irq_handler_asynch(spi_t *obj)
{
    // use the right instance
    SPI_HandleTypeDef *handle = &SpiHandle[obj->spi.module];
    int event = 0;

    // call the CubeF4 handler, this will update the handle
    HAL_SPI_IRQHandler(handle);

    if (HAL_SPI_GetState(handle) == HAL_SPI_STATE_READY) {
        // adjust buffer positions
        size_t tx_size = (handle->TxXferSize - handle->TxXferCount);
        size_t rx_size = (handle->RxXferSize - handle->RxXferCount);
        // 16 bit transfers need to be doubled to get bytes
        if (handle->Init.DataSize == SPI_DATASIZE_16BIT) {
            tx_size *= 2;
            rx_size *= 2;
        }
        // adjust buffer positions
        if (obj->spi.transfer_type != SPI_TRANSFER_TYPE_RX) {
            obj->tx_buff.pos += tx_size;
        }
        if (obj->spi.transfer_type != SPI_TRANSFER_TYPE_TX) {
            obj->rx_buff.pos += rx_size;
        }

        if (handle->TxXferCount > 0) DEBUG_PRINTF("SPI%u: TxXferCount: %u\n", obj->spi.module+1, handle->TxXferCount);
        if (handle->RxXferCount > 0) DEBUG_PRINTF("SPI%u: RxXferCount: %u\n", obj->spi.module+1, handle->RxXferCount);

        int error = HAL_SPI_GetError(handle);
        if(error != HAL_SPI_ERROR_NONE) {
            // something went wrong and the transfer has definitely completed
            event = SPI_EVENT_ERROR | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;

            if (error & HAL_SPI_ERROR_OVR) {
                // buffer overrun
                event |= SPI_EVENT_RX_OVERFLOW;
            }
        } else {
            // figure out if we need to transfer more data:
            if (obj->tx_buff.pos < obj->tx_buff.length) {
                // DEBUG_PRINTF("t%u ", obj->tx_buff.pos);
                // we need to transfer more data
                spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX,
                    obj->tx_buff.buffer + obj->tx_buff.pos,     // offset the initial buffer by the position
                    NULL,                                       // there is no receive buffer
                    obj->tx_buff.length - obj->tx_buff.pos);    // transfer the remaining bytes only
            } else if (obj->rx_buff.pos < obj->rx_buff.length) {
                // DEBUG_PRINTF("r%u ", obj->rx_buff.pos);
                // we need to receive more data
                spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX,
                    NULL,                                       // there is no transmit buffer
                    obj->rx_buff.buffer + obj->rx_buff.pos,     // offset the initial buffer by the position
                    obj->rx_buff.length - obj->rx_buff.pos);    // transfer one byte at a time, until we received everything
            } else {
                // everything is ok, nothing else needs to be transferred
                event = SPI_EVENT_COMPLETE | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
                DEBUG_PRINTF("SPI%u: Done: %u, %u\n", obj->spi.module+1, obj->tx_buff.pos, obj->rx_buff.pos);
            }
        }
    }

    if (event) DEBUG_PRINTF("SPI%u: Event: 0x%x\n", obj->spi.module+1, event);

    return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));
}