Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teach DMA to transfer n bytes n times #666

Closed
TomSaw opened this issue Jul 30, 2021 · 6 comments
Closed

Teach DMA to transfer n bytes n times #666

TomSaw opened this issue Jul 30, 2021 · 6 comments

Comments

@TomSaw
Copy link
Contributor

TomSaw commented Jul 30, 2021

🔥 Here's the # 666 hell 😈 of a feature-request 🔥

To accelerate the graphic APIs clear(Color color) methods i need the following DMA feature.
See #665

Application 1: clear external CGRAM (Display-RAM) with DMA:

// Desired method with repeat parameter
SpiMaster1_Dma::transfer(const uint8_t *tx, uint8_t *rx, std::size_t length, size_t repeat);

// Example usage sending: 0xAA, 0xBB, 0xAA, 0xBB, 0xAA, 0xBB, 0xAA, 0xBB, 0xAA, 0xBB, ... (128 times)
uint8_t buffer[2] = {0xAA, 0xBB};
SpiMaster1_Dma::transfer(buffer, nullptr, 2, 128);

Application 2: Substitute std::fill(..)

Similar to Application 1 but for internal RAM

Possible Implementation!?

Sending repeated bytes is easy: Just disable the DMAs address-incement for the read. Sending repeated multi-byte sequences is not so easy. I think STMs Circular DMA Mode can be utilized here.

Whats your guess @chris-durand / @mikewolfram / @salkinium ? I've recognized your recent effort with DMA.

@TomSaw TomSaw changed the title Teach DMA to send n bytes n times Teach DMA to trasnfer n bytes n times Jul 31, 2021
@mikewolfram
Copy link
Contributor

I had a quick look into the L4 reference manual. If I interpret the SPI chapter correctly, then it should be possible to write a 16bit value to an 8bit SPI (DMA packing on SPI, pages 1316 and 1318). With pointer incrementing disabled this would allow to set the pixel color for a predefined area. But requires reconfiguration of the DMA channel before sending.

The problem with circular mode is the never ending transfer. You'd need to count the loops and disable the transfer when done. If going that path it would be preferable to use a small buffer for the transfer to reduce the overhead of the DMA IRQ handler being called after every byte/word.

@TomSaw TomSaw changed the title Teach DMA to trasnfer n bytes n times Teach DMA to transfer n bytes n times Aug 4, 2021
@TomSaw
Copy link
Contributor Author

TomSaw commented Aug 6, 2021

Ah nice! Thanks for the hint mike, I'll gonna try this out.

Additional note:
For the graphic usecase, the highest expected value for repeat is 3
Maximum color depth used for simple displays: 24bpp -> 3 bytes.

@salkinium
Copy link
Member

salkinium commented Aug 6, 2021

At least for STM32 DMA you can make it read 16- or 32-bits (but not 24-bits), but only write 8-bits with the DMA buffering the value in between, so this may work even without anything special.

I would however, focus on DMA2D first, since replacing parts of libc(++) isn't trivial and the overhead of setting up DMA for small buffers is bigger than memset/memcpy. You also need a future/promise mechanism so you can do useful CPU work while you wait for DMA to finish. Never mind, you only need it for SPI transfers, not in general.

@TomSaw
Copy link
Contributor Author

TomSaw commented Aug 9, 2021

Si. Let's keep std::fill, it's fine.

The OLEDs actually don't have an internal buffer. If I can't implement a 'clear()' working this way, I need to add a (little) buffer just for clearing the noize on power-up witch is stupid.

@TomSaw
Copy link
Contributor Author

TomSaw commented Sep 13, 2021

I have expanded this task and added bit-resolution to each transfer<4-16>(...) of SPI.
All in #690

@TomSaw
Copy link
Contributor Author

TomSaw commented Sep 14, 2021

OMG 🤩 this uint16_t / 16bit Spi::transfer(...) - described in my previous comment - really is a central missing gear. Look at this refreshed Touch2046::getRawValues():

Before

template < class SpiMaster, class Cs >
modm::ResumableResult<std::tuple<uint16_t,uint16_t,uint16_t>>
modm::Touch2046<SpiMaster, Cs>::getRawValues()
{
	RF_BEGIN();

	RF_WAIT_UNTIL(this->acquireMaster());
	Cs::reset();

	RF_CALL(SpiMaster::transfer(
		bufferWrite.data(),
		reinterpret_cast<uint8_t*>(bufferRead.data()) + 1,
		17));

	z = 4095 + (modm::fromBigEndian(bufferRead[1]) >> 3)
		- (modm::fromBigEndian(bufferRead[2]) >> 3);

	y = (modm::fromBigEndian(bufferRead[3]) >> 3)
		+ (modm::fromBigEndian(bufferRead[5]) >> 3)
		+ (modm::fromBigEndian(bufferRead[7]) >> 3);

	x = (modm::fromBigEndian(bufferRead[4]) >> 3)
		+ (modm::fromBigEndian(bufferRead[6]) >> 3)
		+ (modm::fromBigEndian(bufferRead[8]) >> 3);

	if (this->releaseMaster()) {
		Cs::set();
	}

	RF_END_RETURN(std::make_tuple(x, y, z));
}

After

template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<std::tuple<uint16_t, uint16_t, uint16_t>>
modm::Touch2046<SpiMaster, Cs, R>::getRawValues()
{
	RF_BEGIN();

	RF_WAIT_UNTIL(this->acquireMaster());
	Cs::reset();

	RF_CALL(SpiMaster::template transfer<16>(bufferWrite.data(), bufferRead.data(), bufferWrite.size()));

	z = 4095 + (bufferRead[1] >> 3) - (bufferRead[2] >> 3);
	y = (bufferRead[3] >> 3) + (bufferRead[5] >> 3) + (bufferRead[7] >> 3);
	x = (bufferRead[4] >> 3) + (bufferRead[6] >> 3) + (bufferRead[8] >> 3);

	if (this->releaseMaster())
		Cs::set();

	RF_END_RETURN(std::make_tuple(x, y, z));
}

@TomSaw TomSaw changed the title Teach DMA to transfer n bytes n times Bit resolution Spi + Routine to transfer same data mulitple times Sep 14, 2021
@TomSaw TomSaw changed the title Bit resolution Spi + Routine to transfer same data mulitple times Bit resolution Spi + Routine to transfer same data multiple times Sep 14, 2021
@TomSaw TomSaw changed the title Bit resolution Spi + Routine to transfer same data multiple times Teach DMA to transfer n bytes n times Sep 15, 2021
@TomSaw TomSaw closed this as completed Sep 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants