mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-05 09:38:10 +00:00
199 lines
5.9 KiB
C++
199 lines
5.9 KiB
C++
/******************************************************************************
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
* @file libmaple/sdio.c
|
|
* @author stevstrong
|
|
* @brief Secure digital input/output interface.
|
|
*/
|
|
|
|
#include <libmaple/sdio.h>
|
|
#include <libmaple/gpio.h>
|
|
#include <boards.h>
|
|
#include "wirish.h"
|
|
|
|
|
|
//#include <libmaple/libmaple.h>
|
|
//#include <libmaple/rcc.h>
|
|
//#include <series/gpio.h>
|
|
//#include "wirish.h"
|
|
//#include "boards.h"
|
|
//
|
|
|
|
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
|
|
|
|
sdio_dev * SDIO = SDIO_BASE;
|
|
|
|
#define DELAY_LONG 10
|
|
#define DELAY_SHORT 1
|
|
|
|
uint8_t dly = DELAY_LONG; // microseconds delay after accessing registers
|
|
|
|
/*
|
|
* SDIO convenience routines
|
|
*/
|
|
void sdio_gpios_init(void)
|
|
{
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_AF_OUTPUT_PP);
|
|
/*
|
|
* Todo just remove it, not needed for F1.
|
|
*/
|
|
/*
|
|
gpio_set_af_mode(BOARD_SDIO_D0, 12);
|
|
gpio_set_af_mode(BOARD_SDIO_D1, 12);
|
|
gpio_set_af_mode(BOARD_SDIO_D2, 12);
|
|
gpio_set_af_mode(BOARD_SDIO_D3, 12);
|
|
gpio_set_af_mode(BOARD_SDIO_CLK, 12);
|
|
gpio_set_af_mode(BOARD_SDIO_CMD, 12);
|
|
*/
|
|
}
|
|
|
|
void sdio_gpios_deinit(void)
|
|
{
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D0].gpio_device, PIN_MAP[BOARD_SDIO_D0].gpio_bit, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D1].gpio_device, PIN_MAP[BOARD_SDIO_D1].gpio_bit, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D2].gpio_device, PIN_MAP[BOARD_SDIO_D2].gpio_bit, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_D3].gpio_device, PIN_MAP[BOARD_SDIO_D3].gpio_bit, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_CLK].gpio_device, PIN_MAP[BOARD_SDIO_CLK].gpio_bit, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(PIN_MAP[BOARD_SDIO_CMD].gpio_device, PIN_MAP[BOARD_SDIO_CMD].gpio_bit, GPIO_INPUT_FLOATING);
|
|
|
|
/*
|
|
* Todo just remove it, not needed for F1.
|
|
*/
|
|
/*
|
|
gpio_set_af_mode(BOARD_SDIO_D0, 0);
|
|
gpio_set_af_mode(BOARD_SDIO_D1, 0);
|
|
gpio_set_af_mode(BOARD_SDIO_D2, 0);
|
|
gpio_set_af_mode(BOARD_SDIO_D3, 0);
|
|
gpio_set_af_mode(BOARD_SDIO_CLK, 0);
|
|
gpio_set_af_mode(BOARD_SDIO_CMD, 0);
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize and reset the SDIO device.
|
|
*/
|
|
void sdio_init(void)
|
|
{
|
|
rcc_clk_enable(RCC_SDIO);
|
|
rcc_reset_dev(RCC_SDIO);
|
|
}
|
|
|
|
void sdio_power_on(void)
|
|
{
|
|
SDIO->POWER = SDIO_POWER_PWRCTRL_ON;
|
|
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
|
// plus two PCLK2 clock periods.
|
|
delay_us(DELAY_LONG);
|
|
}
|
|
|
|
void sdio_power_off(void)
|
|
{
|
|
SDIO->POWER = SDIO_POWER_PWRCTRL_OFF;
|
|
// After a data write, data cannot be written to this register for three SDIOCLK clock periods
|
|
// plus two PCLK2 clock periods.
|
|
delay_us(DELAY_LONG);
|
|
}
|
|
|
|
void sdio_set_clock(uint32_t clk)
|
|
{
|
|
if (clk>24000000UL) clk = 24000000UL; // limit the SDIO master clock to 24MHz
|
|
|
|
if (clk<1000000) dly = DELAY_LONG;
|
|
else dly = DELAY_SHORT;
|
|
|
|
sdio_disable();
|
|
SDIO->CLKCR = (SDIO->CLKCR & (~(SDIO_CLKCR_CLKDIV|SDIO_CLKCR_BYPASS))) | SDIO_CLKCR_CLKEN | (((SDIOCLK/clk)-2)&SDIO_CLKCR_CLKDIV);
|
|
delay_us(dly);
|
|
}
|
|
|
|
void sdio_set_dbus_width(uint16_t bus_w)
|
|
{
|
|
SDIO->CLKCR = (SDIO->CLKCR & (~SDIO_CLKCR_WIDBUS)) | bus_w;
|
|
delay_us(dly);
|
|
}
|
|
|
|
void sdio_set_dblock_size(uint8_t dbsize)
|
|
{
|
|
SDIO->DCTRL = (SDIO->DCTRL&(~SDIO_DCTRL_DBLOCKSIZE)) | ((dbsize&0xF)<<4);
|
|
delay_us(dly);
|
|
}
|
|
|
|
void sdio_enable(void)
|
|
{
|
|
SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
|
|
delay_us(dly);
|
|
}
|
|
|
|
void sdio_disable(void)
|
|
{
|
|
SDIO->CLKCR ^= SDIO_CLKCR_CLKEN;
|
|
delay_us(dly);
|
|
}
|
|
|
|
/**
|
|
* @brief Configure and enable the SDIO device.
|
|
*/
|
|
void sdio_begin(void)
|
|
{
|
|
sdio_gpios_init();
|
|
sdio_init();
|
|
sdio_power_on();
|
|
// Set initial SCK rate.
|
|
sdio_set_clock(400000);
|
|
delay_us(200); // generate 80 pulses at 400kHz
|
|
}
|
|
|
|
/**
|
|
* @brief Disables the SDIO device.
|
|
*/
|
|
void sdio_end(void)
|
|
{
|
|
sdio_disable();
|
|
while ( sdio_cmd_xfer_ongoing() );
|
|
sdio_power_off();
|
|
rcc_clk_disable(RCC_SDIO);
|
|
sdio_gpios_deinit();
|
|
}
|
|
|
|
/**
|
|
* @brief Send command by the SDIO device.
|
|
*/
|
|
uint8_t sdio_cmd_send(uint16_t cmd_index_resp_type, uint32_t arg)
|
|
{
|
|
uint8_t retries = 10; // in case of errors
|
|
do { // retry command if errors detected
|
|
// clear interrupt flags - IMPORTANT!!!
|
|
SDIO->ICR = SDIO_ICR_CMD_FLAGS;
|
|
// write command
|
|
SDIO->ARG = arg;
|
|
SDIO->CMD = (uint32_t)(SDIO_CMD_CPSMEN | cmd_index_resp_type );
|
|
while ( (SDIO->STA&SDIO_STA_CMDACT) ) ; // wait for actual command transfer to finish
|
|
// wait for response, if the case
|
|
if ( cmd_index_resp_type&(SDIO_CMD_WAIT_SHORT_RESP|SDIO_CMD_WAIT_LONG_RESP) ) {
|
|
while ( !(SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CMD_ERROR_FLAGS)) ) ;
|
|
} else break; // no response required
|
|
if ( SDIO->STA&(SDIO_STA_CMDREND|SDIO_STA_CTIMEOUT) )
|
|
break; // response received or timeout
|
|
// ignore CRC error for CMD5 and ACMD41
|
|
if ( ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==5) || ((cmd_index_resp_type&SDIO_CMD_CMDINDEX)==41) )
|
|
break;
|
|
} while ( (--retries) );
|
|
return (uint8_t)retries;
|
|
}
|
|
|
|
#endif // defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
|