Spark Logic

"bit bang" SPI pins STM32F1

alexandros Mon Oct 09, 2017 10:09 am

Hello ,
i have a project that i use SPI1 in order to transfer data ,
PA7 MOSI1
PA6 MISO1
PA5 SCK1
PA4 NSS1

the board that i m using is hard to reach the MOSI pin PA7 basically its not breaked out anywhere i have to solder over MCU , i have access to PA6 though ,
So i am wondering before i make my next move , Is there any quick and easy way to Bit Bang data from MOSI1 to MISO1 ,

Replies

Pito Mon Oct 09, 2017 10:12 am

You may bitbang any pins with bitbanged SPI.

alexandros Mon Oct 09, 2017 10:15 am

I guess that is a hopeful answer :)
any example out there will save me tons of hours

Pito Mon Oct 09, 2017 10:35 am

In order to save 4 tons of your time:
https://github.com/nickgammon/bitBangedSPI

I’ve been using it with max7219 and BluePill and it works.

Something like this (not tested this way, you have to spend some pounds of time to elaborate):

// bitBangedSPI (const int mosi, const int miso, const int sck, const unsigned long delayUs = 4)
bitBangedSPI bbSPI(PA33, PA44, PA55);
..
bbSPI.begin();
..
inbyte = bbSPI.transfer(outbyte);
..

alexandros Mon Oct 09, 2017 11:29 am

Thanks man i apreciated.
I am porting it into my code , i ll see how it goes.

stevestrong Mon Oct 09, 2017 11:34 am

Before using software SPI, you should maybe first consider remapping of the SPI pins, if those remapped pins are available:
F1_SPI1_remap.jpg
F1_SPI1_remap.jpg (53.11 KiB) Viewed 551 times

dannyf Mon Oct 09, 2017 12:12 pm

Is there any quick and easy way to Bit Bang data from MOSI1 to MISO1 ,

not sure what that means.

you can certainly bitbang any pins but if the pin isn’t routed out, not sure if it is instead better to bitbang a pin that is routed out.

alexandros Mon Oct 09, 2017 1:02 pm

[stevestrong – Mon Oct 09, 2017 11:34 am] –
Before using software SPI, you should maybe first consider remapping of the SPI pins, if those remapped pins are available:
F1_SPI1_remap.jpg

NSS is not relevant though.

Image

In my case i want PA6 as MOSI . i want only to send data , the alternate pins (PB5,PB4,PB3….) of SPI1 are not available with my equipment . (at least not breaked out) bad luck i guess.

just ported the code without errors , i ll check later if my data pass through PA6 ..

stevestrong Mon Oct 09, 2017 1:21 pm

That code uses digitalWrite() function to toggle the pin level.
If speed is not a concern for you, then it should be fine.
Otherwise you should use direct memory writes to toggle the pins.

alexandros Mon Oct 09, 2017 2:58 pm

[stevestrong – Mon Oct 09, 2017 1:21 pm] –
That code uses digitalWrite() function to toggle the pin level.
If speed is not a concern for you, then it should be fine.
Otherwise you should use direct memory writes to toggle the pins.

I think that the Speed is too slow.. :o
How can i use direct memory writes ? any example?”

Pito Mon Oct 09, 2017 3:15 pm

Comment out all delays if you need more speed (bitBangedSPI.cpp):
// clock high
digitalWrite (sck_, HIGH);

// delay between rise and fall of clock
delayMicroseconds (delayUs_);

// clock low
digitalWrite (sck_, LOW);

// delay between rise and fall of clock
delayMicroseconds (delayUs_);
} // end of for loop, for each bit

dannyf Mon Oct 09, 2017 3:34 pm

the following:

//transmission on sck's rising edge
void spi1_write(unsigned char data_t) {
unsigned char mask = 0x80; //start with the most signifcant bit

#if defined(SPI1_MOSI)
IO_OUT(SPI1_DDR, SPI1_MOSI); //mosi as output
#endif
IO_CLR(SPI1_PORT, SPI1_SCK); //default state of sck: low
while (mask) {
IO_CLR(SPI1_PORT, SPI1_SCK); //clear spi_sck

#if defined(SPI1_MOSI)
if (data_t & mask) IO_SET(SPI1_PORT, SPI1_MOSI); //send the data
else IO_CLR(SPI1_PORT, SPI1_MOSI);
#endif
IO_SET(SPI1_PORT, SPI1_SCK); //send on the rising edge
SPI1_DELAY(SPI1_DLY); //insert some delays to generate 50% dc
mask = mask >> 1; //next bit
}
//IO_CLR(SPI1_PORT, SPI1_MOSI); //clear mosi
//IO_CLR(SPI1_PORT, SPI1_SCK); //clear sck
}

alexandros Mon Oct 09, 2017 6:19 pm

[Pito – Mon Oct 09, 2017 3:15 pm] –
Comment out all delays if you need more speed (bitBangedSPI.cpp):

First try to use this code, when you gather more experience with stm32 you may replace the digitalWrite()..

I just tried it , i do see some speed but , this isnt the issue though.

i suspect that i am making something wrong , and i guess its the intrerupt that i am not taking care of , so i will post my code in order to get things straigh,

So my normal code before the bit bang is

........
dma_init(SPIDMA_1);
dma_attach_interrupt(SPIDMA_1, DMA_CH3, &DMA1_CH3_handler);
spi_tx_dma_enable(SPI_Class->dev());
.......

// Interrupt handler for DMA (clear data output)
void DMA1_CH3_handler()
{
while(SPI_Class->dev()->regs->SR & SPI_SR_BSY);
SPI_Class->dev()->regs->DR = 0;
}

///SEND DATA
void SPI_dmaSend(uint8_t *transmitBuffer, uint16_t length) {
//DATA SEND INTO PA7 MOSI1
dma_setup_transfer(
SPIDMA_1, DMA_CH3, // DMA channel specification for SPI 1
&SPI_Class->dev()->regs->DR, // destination address: specify the SPI data register
DMA_SIZE_8BITS, // ​​Destination data size: 1 byte
transmitBuffer, // source address: SRAM address
DMA_SIZE_8BITS, // ​​Destination data size: 1 byte
DMA_MINC_MODE| // flag: cyclic
DMA_FROM_MEM | // Peripheral from memory, transfer complete interrupted
DMA_TRNS_CMPLT // Transfer complete Interrupted calling * /
);
dma_set_num_transfers(SPIDMA_1, DMA_CH3, length);
dma_enable(SPIDMA_1, DMA_CH3);
}

stevestrong Mon Oct 09, 2017 7:32 pm

Why do you “reinvent the wheel”?
We have already an hardware SPI library which supports DMA: https://github.com/rogerclarkmelbourne/ … raries/SPI

As far as I know, the software (bit-bang) SPI cannot work with DMA.

You still haven’t mentioned in clear text what is your issue.
“It does not work” is not enough information.

RogerClark Mon Oct 09, 2017 8:54 pm

Is your MCU acting as the Master or the Slave?

You are implying that you want the MCU to use the slave connections.

Did you build the hardware yourself?

If not… There must be a good reason for the manufacturer to use a non standard pin configuration

alexandros Mon Oct 09, 2017 9:17 pm

[RogerClark – Mon Oct 09, 2017 8:54 pm] –
Is your MCU acting as the Master or the Slave?

You are implying that you want the MCU to use the slave connections.

Did you build the hardware yourself?

If not… There must be a good reason for the manufacturer to use a non standard pin configuration

if i understand the question corectly , Yes my MCU acting as the Master,
i already manage to use the alternate pins of SPI1 pb5 ,pb4 ,pb3 etc
afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); // release PB3 and PB5
afio_remap(AFIO_REMAP_SPI1); // remap SPI1
gpio_set_mode(GPIOB, 5, GPIO_AF_OUTPUT_PP);
gpio_set_mode(GPIOB, 3, GPIO_AF_OUTPUT_PP);
gpio_set_mode(GPIOB, 4, GPIO_INPUT_FLOATING);
gpio_set_mode(GPIOB, 3, GPIO_AF_OUTPUT_PP);

RogerClark Mon Oct 09, 2017 9:38 pm

OK.

What is the hardware ?

alexandros Mon Oct 09, 2017 9:51 pm

a chinese controller for 3d printer

RogerClark Mon Oct 09, 2017 11:37 pm

OK

stevestrong Tue Oct 10, 2017 8:42 am

Let me conclude:
You want to use a non-standard configuration of the SPI: outputting MOSI data on MISO pin.
That means, you have to forget any available hardware solution, forget the hardware SPI library, and forget DMA.

Available solution: software SPI (bit-banging), using the available soft SPI library – in this case, too, forget DMA.
Unlesss you decompose each bit of a data byte to a separate 16 bit data in the memory and trigger the DMA by a timer to send the decomposed 16 bits to the BSRR register directly. It is complicated, and the overhead to prepare the decomposed data in memory would cost you more time than just directly bit-bang the data out to the peripheral.

For GPIO fast output using direct register access please see:
– this thread: http://stm32duino.com/viewtopic.php?f=18&t=303
– or check an available solution (16 bit parallel LCD library): https://github.com/stevstrong/Adafruit_ … M32.h#L116

Sign in to reply