support linux system

This commit is contained in:
ZYQ-FEIYUE
2022-08-09 22:38:26 +08:00
parent ef453b4ba6
commit d2816d24b5
130 changed files with 22 additions and 24 deletions

430
cores/arduino/SPI.cpp Normal file
View File

@@ -0,0 +1,430 @@
/*
* MIT License
* Copyright (c) 2017 - 2022 _VIFEXTech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* 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.
*/
#include "SPI.h"
#define SPI1_CLOCK (F_CPU)
#define SPI2_CLOCK (F_CPU)
#define SPI3_CLOCK (F_CPU)
SPIClass::SPIClass(spi_type* spix)
: SPIx(spix)
, SPI_Clock(0)
{
memset(&spi_init_struct, 0, sizeof(spi_init_struct));
}
void SPIClass::SPI_Settings(
spi_master_slave_mode_type master_slave_mode,
spi_frame_bit_num_type frame_bit_num,
uint16_t SPI_MODEx,
spi_cs_mode_type cs_mode,
spi_mclk_freq_div_type mclk_freq_div,
spi_first_bit_type first_bit)
{
spi_clock_polarity_type clock_polarity;
spi_clock_phase_type clock_phase;
spi_enable(SPIx, FALSE);
switch(SPI_MODEx)
{
case 0:
clock_polarity = SPI_CLOCK_POLARITY_LOW;
clock_phase = SPI_CLOCK_PHASE_1EDGE;
break;
case 1:
clock_polarity = SPI_CLOCK_POLARITY_LOW;
clock_phase = SPI_CLOCK_PHASE_2EDGE;
break;
case 2:
clock_polarity = SPI_CLOCK_POLARITY_HIGH;
clock_phase = SPI_CLOCK_PHASE_1EDGE;
break;
case 3:
clock_polarity = SPI_CLOCK_POLARITY_HIGH;
clock_phase = SPI_CLOCK_PHASE_2EDGE;
break;
default:
return;
}
spi_default_para_init(&spi_init_struct);
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_init_struct.master_slave_mode = master_slave_mode;
spi_init_struct.frame_bit_num = frame_bit_num;
spi_init_struct.clock_polarity = clock_polarity;
spi_init_struct.clock_phase = clock_phase;
spi_init_struct.cs_mode_selection = cs_mode;
spi_init_struct.mclk_freq_division = mclk_freq_div;
spi_init_struct.first_bit_transmission = first_bit;
spi_init(SPIx, &spi_init_struct);
spi_enable(SPIx, TRUE);
}
void SPIClass::begin(void)
{
spi_i2s_reset(SPIx);
if(SPIx == SPI1)
{
SPI_Clock = SPI1_CLOCK;
crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
pinMode(PA5, OUTPUT_AF_PP);
pinMode(PA6, OUTPUT_AF_PP);
pinMode(PA7, OUTPUT_AF_PP);
}
else if(SPIx == SPI2)
{
SPI_Clock = SPI2_CLOCK;
crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
pinMode(PB13, OUTPUT_AF_PP);
pinMode(PB14, OUTPUT_AF_PP);
pinMode(PB15, OUTPUT_AF_PP);
}
else if(SPIx == SPI3)
{
SPI_Clock = SPI3_CLOCK;
crm_periph_clock_enable(CRM_SPI3_PERIPH_CLOCK, TRUE);
pinMode(PB3, OUTPUT_AF_PP);
pinMode(PB4, OUTPUT_AF_PP);
pinMode(PB5, OUTPUT_AF_PP);
}
else
{
return;
}
SPI_Settings(
SPI_MODE_MASTER,
SPI_FRAME_8BIT,
SPI_MODE0,
SPI_CS_SOFTWARE_MODE,
SPI_MCLK_DIV_8,
SPI_FIRST_BIT_MSB
);
}
void SPIClass::begin(uint32_t clock, uint16_t dataOrder, uint16_t dataMode)
{
begin();
setClock(clock);
setBitOrder(dataOrder);
setDataMode(dataMode);
spi_enable(SPIx, TRUE);
}
void SPIClass::begin(SPISettings settings)
{
begin();
setClock(settings.clock);
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
spi_enable(SPIx, TRUE);
}
void SPIClass::beginSlave(void)
{
begin();
SPI_Settings(
SPI_MODE_SLAVE,
SPI_FRAME_8BIT,
SPI_MODE0,
SPI_CS_SOFTWARE_MODE,
SPI_MCLK_DIV_16,
SPI_FIRST_BIT_MSB
);
spi_enable(SPIx, TRUE);
}
void SPIClass::end(void)
{
spi_enable(SPIx, FALSE);
}
void SPIClass::setClock(uint32_t clock)
{
if(clock == 0)
{
return;
}
static const spi_mclk_freq_div_type mclk_freq_div_map[] =
{
SPI_MCLK_DIV_2,
SPI_MCLK_DIV_2,
SPI_MCLK_DIV_4,
SPI_MCLK_DIV_8,
SPI_MCLK_DIV_16,
SPI_MCLK_DIV_32,
SPI_MCLK_DIV_64,
SPI_MCLK_DIV_128,
SPI_MCLK_DIV_256,
SPI_MCLK_DIV_512,
SPI_MCLK_DIV_1024,
};
const uint8_t mapSize = sizeof(mclk_freq_div_map) / sizeof(mclk_freq_div_map[0]);
uint32_t clockDiv = SPI_Clock / clock;
uint8_t mapIndex = 0;
while(clockDiv > 1)
{
clockDiv = clockDiv >> 1;
mapIndex++;
}
if(mapIndex >= mapSize)
{
mapIndex = mapSize - 1;
}
spi_init_struct.mclk_freq_division = mclk_freq_div_map[mapIndex];
spi_init(SPIx, &spi_init_struct);
spi_enable(SPIx, TRUE);
}
void SPIClass::setClockDivider(uint32_t Div)
{
if(Div == 0)
{
Div = 1;
}
#if SPI_CLASS_AVR_COMPATIBILITY_MODE
setClock(16000000 / Div); // AVR:16MHz
#else
setClock(SPI_Clock / Div);
#endif
}
void SPIClass::setBitOrder(uint16_t bitOrder)
{
spi_init_struct.first_bit_transmission = (bitOrder == MSBFIRST) ? SPI_FIRST_BIT_MSB : SPI_FIRST_BIT_LSB;
spi_init(SPIx, &spi_init_struct);
spi_enable(SPIx, TRUE);
}
/* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly.
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
*
*/
void SPIClass::setDataSize(uint32_t datasize)
{
spi_init_struct.frame_bit_num = (spi_frame_bit_num_type)datasize;
spi_init(SPIx, &spi_init_struct);
spi_enable(SPIx, TRUE);
}
void SPIClass::setDataMode(uint8_t dataMode)
{
/* Notes. As far as I can tell, the AVR numbers for dataMode appear to match the numbers required by the STM32
From the AVR doc http://www.atmel.com/images/doc2585.pdf section 2.4
SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge
0 0 0 Falling Rising
1 0 1 Rising Falling
2 1 0 Rising Falling
3 1 1 Falling Rising
On the STM32 it appears to be
bit 1 - CPOL : Clock polarity
(This bit should not be changed when communication is ongoing)
0 : CLK to 0 when idle
1 : CLK to 1 when idle
bit 0 - CPHA : Clock phase
(This bit should not be changed when communication is ongoing)
0 : The first clock transition is the first data capture edge
1 : The second clock transition is the first data capture edge
If someone finds this is not the case or sees a logic error with this let me know ;-)
*/
spi_clock_polarity_type clock_polarity;
spi_clock_phase_type clock_phase;
spi_enable(SPIx, FALSE);
switch(dataMode)
{
case 0:
clock_polarity = SPI_CLOCK_POLARITY_LOW;
clock_phase = SPI_CLOCK_PHASE_1EDGE;
break;
case 1:
clock_polarity = SPI_CLOCK_POLARITY_LOW;
clock_phase = SPI_CLOCK_PHASE_2EDGE;
break;
case 2:
clock_polarity = SPI_CLOCK_POLARITY_HIGH;
clock_phase = SPI_CLOCK_PHASE_1EDGE;
break;
case 3:
clock_polarity = SPI_CLOCK_POLARITY_HIGH;
clock_phase = SPI_CLOCK_PHASE_2EDGE;
break;
default:
return;
}
spi_init_struct.clock_polarity = clock_polarity;
spi_init_struct.clock_phase = clock_phase;
spi_init(SPIx, &spi_init_struct);
spi_enable(SPIx, TRUE);
}
void SPIClass::beginTransaction(SPISettings settings)
{
SPISettings(settings.clock, settings.bitOrder, settings.dataMode);
setClock(settings.clock);
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setDataSize(settings.dataSize);
spi_enable(SPIx, TRUE);
}
void SPIClass::beginTransactionSlave(void)
{
beginSlave();
}
void SPIClass::endTransaction(void)
{
spi_enable(SPIx, FALSE);
}
uint16_t SPIClass::read(void)
{
SPI_I2S_WAIT_RX(SPIx);
return (uint16_t)(SPI_I2S_RXDATA(SPIx));
}
void SPIClass::read(uint8_t *buf, uint32_t len)
{
if (len == 0)
return;
SPI_I2S_RXDATA_VOLATILE(SPIx);
SPI_I2S_TXDATA(SPIx, 0x00FF);
while((--len))
{
SPI_I2S_WAIT_TX(SPIx);
noInterrupts();
SPI_I2S_TXDATA(SPIx, 0x00FF);
SPI_I2S_WAIT_RX(SPIx);
*buf++ = (uint8_t)SPI_I2S_RXDATA(SPIx);
interrupts();
}
SPI_I2S_WAIT_RX(SPIx);
*buf++ = (uint8_t)SPI_I2S_RXDATA(SPIx);
}
void SPIClass::write(uint16_t data)
{
SPI_I2S_TXDATA(SPIx, data);
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_WAIT_BUSY(SPIx);
}
void SPIClass::write(uint16_t data, uint32_t n)
{
while ((n--) > 0)
{
SPI_I2S_TXDATA(SPIx, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
SPI_I2S_WAIT_TX(SPIx); // wait till Tx empty
}
SPI_I2S_WAIT_BUSY(SPIx); // wait until BSY=0 before returning
}
void SPIClass::write(const uint8_t *data, uint32_t length)
{
while (length--)
{
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_TXDATA(SPIx, *data++);
}
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_WAIT_BUSY(SPIx);
}
void SPIClass::write(const uint16_t *data, uint32_t length)
{
while (length--)
{
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_TXDATA(SPIx, *data++);
}
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_WAIT_BUSY(SPIx);
}
uint8_t SPIClass::transfer(uint8_t wr_data) const
{
SPI_I2S_RXDATA_VOLATILE(SPIx);
SPI_I2S_TXDATA(SPIx, wr_data);
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_WAIT_BUSY(SPIx);
return (uint8_t)SPI_I2S_RXDATA(SPIx);
}
uint16_t SPIClass::transfer16(uint16_t wr_data) const
{
SPI_I2S_RXDATA_VOLATILE(SPIx);
SPI_I2S_TXDATA(SPIx, wr_data);
SPI_I2S_WAIT_TX(SPIx);
SPI_I2S_WAIT_BUSY(SPIx);
return (uint16_t)SPI_I2S_RXDATA(SPIx);
}
uint8_t SPIClass::send(uint8_t data)
{
this->write(data);
return 1;
}
uint8_t SPIClass::send(uint8_t *buf, uint32_t len)
{
this->write(buf, len);
return len;
}
uint8_t SPIClass::recv(void)
{
return this->read();
}
#if SPI_CLASS_1_ENABLE
SPIClass SPI(SPI_CLASS_1_SPI);
#endif
#if SPI_CLASS_2_ENABLE
SPIClass SPI_2(SPI_CLASS_2_SPI);
#endif
#if SPI_CLASS_3_ENABLE
SPIClass SPI_3(SPI_CLASS_3_SPI);
#endif