diff --git a/core/esp_spi.c b/core/esp_spi.c index ab33ea4..720da18 100644 --- a/core/esp_spi.c +++ b/core/esp_spi.c @@ -27,6 +27,7 @@ #define _SPI1_FUNC IOMUX_FUNC(2) #define _SPI_BUF_SIZE 64 +#define __min(a,b) ((a > b) ? (b):(a)) static bool _minimal_pins[2] = {false, false}; @@ -244,3 +245,36 @@ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len return len; } + +static void _repeat_send(uint8_t bus, uint32_t* dword,int32_t* repeats,spi_word_size_t size) +{ + uint8_t i = 0 ; + while(*repeats > 0) + { + uint16_t bytes_to_transfer = __min(*repeats * size , _SPI_BUF_SIZE); + _wait(bus); + _set_size(bus,bytes_to_transfer); + for(i = 0; i < (bytes_to_transfer + 3) / 4;i++) + SPI(bus).W[i] = *dword; //need test with memcpy ! + _start(bus); + *repeats -= (bytes_to_transfer / size ) ; + } + _wait(bus); +} + +void spi_repeat_send_8(uint8_t bus, uint8_t data,int32_t repeats) +{ + uint32_t dword = data << 24 | data << 16 | data << 8 | data; + _repeat_send(bus,&dword,&repeats, SPI_8BIT); +} + +void spi_repeat_send_16(uint8_t bus, uint16_t data,int32_t repeats) +{ + uint32_t dword = data << 16 | data; + _repeat_send(bus,&dword,&repeats, SPI_16BIT); +} + +void spi_repeat_send_32(uint8_t bus, uint32_t data,int32_t repeats) +{ + _repeat_send(bus,&data,&repeats, SPI_32BIT); +} diff --git a/core/include/esp/spi.h b/core/include/esp/spi.h index b3bc629..4b31144 100644 --- a/core/include/esp/spi.h +++ b/core/include/esp/spi.h @@ -36,6 +36,15 @@ #define SPI_FREQ_DIV_40M SPI_GET_FREQ_DIV(1, 2) ///< 40MHz #define SPI_FREQ_DIV_80M SPI_GET_FREQ_DIV(1, 1) ///< 80MHz +/* + * Possible Data Structure of SPI Transaction + * + * [COMMAND]+[ADDRESS]+[DataOUT]+[DUMMYBITS]+[DataIN] + * + * [COMMAND]+[ADDRESS]+[DUMMYBITS]+[DataOUT] + * + */ + #ifdef __cplusplus extern "C" { @@ -177,7 +186,7 @@ void spi_set_frequency_div(uint8_t bus, uint32_t divider); inline uint32_t spi_get_frequency_div(uint8_t bus) { return (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) | - (FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1); + (FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1); } /** * \brief Get SPI bus frequency in Hz @@ -187,8 +196,8 @@ inline uint32_t spi_get_frequency_div(uint8_t bus) inline uint32_t spi_get_frequency_hz(uint8_t bus) { return APB_CLK_FREQ / - (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) / - (FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1); + (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) / + (FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1); } /** @@ -221,8 +230,8 @@ void spi_set_endianness(uint8_t bus, spi_endianness_t endianness); inline spi_endianness_t spi_get_endianness(uint8_t bus) { return SPI(bus).USER0 & (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER) - ? SPI_BIG_ENDIAN - : SPI_LITTLE_ENDIAN; + ? SPI_BIG_ENDIAN + : SPI_LITTLE_ENDIAN; } /** @@ -265,6 +274,129 @@ uint32_t spi_transfer_32(uint8_t bus, uint32_t data); */ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size); +/** + * \brief Add permanent command bits when transfert data over SPI + * Example: + * + * spi_set_command(1,1,0x01); // Set one command bit to 1 + * for (uint8_t i = 0 ; i < x ; i++ ) { + * spi_transfer_8(1,0x55); // Send 1 bit command + 8 bits data x times + * } + * spi_clear_command(1); // Clear command + * spi_transfer_8(1,0x55); // Send 8 bits data + * + * \param bus Bus ID: 0 - system, 1 - user + * \param bits Number of bits (max: 16). + * \param data Command to send for each transfert. + */ +static inline void spi_set_command(uint8_t bus,uint8_t bits, uint16_t data) +{ + if(!bits) return ; + SPI(bus).USER0 |= SPI_USER0_COMMAND ; //enable COMMAND function in SPI module + uint16_t command = data << (16-bits); //align command data to high bits + command = ((command>>8)&0xff) | ((command<<8)&0xff00); //swap byte order + SPI(bus).USER2 = SET_FIELD(SPI(bus).USER2, SPI_USER2_COMMAND_BITLEN, --bits); + SPI(bus).USER2 = SET_FIELD(SPI(bus).USER2, SPI_USER2_COMMAND_VALUE, command); +} + +/** + * \brief Add permanent address bits when transfert data over SPI + * Example: + * + * spi_set_address(1,8,0x45); // Set one address byte to 0x45 + * for (uint8_t i = 0 ; i < x ; i++ ) { + * spi_transfer_16(1,0xC584); // Send 16 bits address + 16 bits data x times + * } + * spi_clear_address(1); // Clear command + * spi_transfer_16(1,0x55); // Send 16 bits data + * + * \param bus Bus ID: 0 - system, 1 - user + * \param bits Number of bits (max: 32). + * \param data Address to send for each transfert. + */ +static inline void spi_set_address(uint8_t bus,uint8_t bits, uint32_t data) +{ + if(!bits) return ; + SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_ADDR_BITLEN, --bits); + SPI(bus).USER0 |= SPI_USER0_ADDR ; //enable ADDRess function in SPI module + SPI(bus).ADDR = data<<(32-bits) ; //align address data to high bits +} + +/** + * \brief Add permanent dummy bits when transfert data over SPI + * Example: + * + * spi_set_dummy_bits(1,4,false); // Set 4 dummy bit before Dout + * for (uint8_t i = 0 ; i < x ; i++ ) { + * spi_transfer_16(1,0xC584); // Send 4 bits dummy + 16 bits Dout x times + * } + * spi_set_dummy_bits(1,4,true); // Set 4 dummy bit between Dout and Din + * spi_transfer_8(1,0x55); // Send 8 bits Dout + 4 bits dummy + 8 bits Din + * + * \param bus Bus ID: 0 - system, 1 - user + * \param bits Number of bits + * \param pos Position of dummy bit, between Dout and Din if true. + */ +static inline void spi_set_dummy_bits(uint8_t bus, uint8_t bits, bool pos) +{ + if(!bits) return ; + if(pos) { SPI(bus).USER0 |= SPI_USER0_MISO; } // Dummy bit will be between Dout and Din data if set + SPI(bus).USER0 |= SPI_USER0_DUMMY; //enable dummy bits + SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_DUMMY_CYCLELEN, --bits); +} + +/** + * \brief Clear adress Bits + * \param bus Bus ID: 0 - system, 1 - user + */ +static inline void spi_clear_address(uint8_t bus) +{ + SPI(bus).USER0 &= ~(SPI_USER0_ADDR) ; +} + +/** + * \brief Clear command Bits + * \param bus Bus ID: 0 - system, 1 - user + */ + +static inline void spi_clear_command(uint8_t bus) +{ + SPI(bus).USER0 &= ~(SPI_USER0_COMMAND) ; +} + +/** + * \brief Clear dummy Bits + * \param bus Bus ID: 0 - system, 1 - user + */ +static inline void spi_clear_dummy(uint8_t bus) +{ + SPI(bus).USER0 &= ~(SPI_USER0_DUMMY | SPI_USER0_MISO); +} + +/** + * \brief Send many 8 bits template over SPI + * \param bus Bus ID: 0 - system, 1 - user + * \param data Byte template (8 bits) + * \param repeats Copy byte number + */ +void spi_repeat_send_8(uint8_t bus, uint8_t data, int32_t repeats); + +/** + * \brief Send many 16 bits template over SPI + * \param bus Bus ID: 0 - system, 1 - user + * \param data Word template (16 bits) + * \param repeats Copy word number + */ +void spi_repeat_send_16(uint8_t bus, uint16_t data, int32_t repeats); + +/** + * \brief Send many 32 bits template over SPI + * \param bus Bus ID: 0 - system, 1 - user + * \param data Dualword template (32 bits) + * \param repeats Copy dword number + */ +void spi_repeat_send_32(uint8_t bus, uint32_t data, int32_t repeats); + #ifdef __cplusplus } #endif diff --git a/examples/spi_test/Makefile b/examples/spi_test/Makefile new file mode 100644 index 0000000..f28ce0c --- /dev/null +++ b/examples/spi_test/Makefile @@ -0,0 +1,3 @@ +# Simple makefile for simple example +PROGRAM=spi_test +include ../../common.mk diff --git a/examples/spi_test/spi_test.c b/examples/spi_test/spi_test.c new file mode 100644 index 0000000..0baccc3 --- /dev/null +++ b/examples/spi_test/spi_test.c @@ -0,0 +1,64 @@ +/* Example SPI transfert + * + * This sample code is in the public domain. + */ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "esp8266.h" +#include +#include "esp/spi.h" + +/* + * Possible Data Structure of SPI Transaction + * + * [COMMAND]+[ADDRESS]+[DataOUT]+[DUMMYBITS]+[DataIN] + * + * [COMMAND]+[ADDRESS]+[DUMMYBITS]+[DataOUT] + * + */ + + +void loop(void *pvParameters) +{ + uint32_t time = 0 ; // SPI transmission time + float avr_time = 0 ; // Average of SPI transmission + float u = 0 ; + + spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_LITTLE_ENDIAN, false); // init SPI module + + + while(1) { + + time = sdk_system_get_time(); + + spi_set_command(1,1,1) ; // Set one command bit to 1 + spi_set_address(1,4,8) ; // Set 4 address bits to 8 + spi_set_dummy_bits(1,4,false); // Set 4 dummy bit before Dout + + spi_repeat_send_16(1,0xC584,10); // Send 1 bit command + 4 bits address + 4 bits dummy + 160 bits data + + spi_clear_address(1); // remove address + spi_clear_command(1); // remove command + spi_clear_dummy(1); // remove dummy + + + time = sdk_system_get_time() -time ; + avr_time = ((avr_time * (float)u ) + (float)time)/((float)u+1.0) ; // compute average + u++; + if (u==100) { + u=0 ; + printf("Time: %f\n",avr_time); + } + vTaskDelay(100/portTICK_PERIOD_MS); + } +} + + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + xTaskCreate(loop, "loop", 1024, NULL, 2, NULL); +}