I know I could wait for the Beads firmware to drop someday… but I’m impatient and would like to use the stm32 audio bootloader very soon for a hobby project I’m working on with the H7… so I thought I’d give it a shot myself!
In addition, I’ve been struggling to get Python 2.5 and an older version of NumPy to run on my Windows machine, which prompted me to go through and update the code for Python 3.8.2 as well.
I feel like I’m super close but I’m noticing some audible differences between the .WAV files my script is creating and the firmware releases on the Mutable site. If anyone is interested in reviewing what I have thus-far, it would be much appreciated. I will share all of this on git for others to use in the future.
Anyway… here is the most-recent version of the code. I’ve tried to tag all of my updates with some justification. You can run the script using run.bat on the testfirmware.bin file I’ve included:
When I run the script, I’m using the following settings:
py encoder.py -t stm32h7 -s 48000 -b 12000 -c 6000 -p 256 testfirmware.bin
The STM32H743xI has two banks of flash memory with eight 128kbytes sectors of memory per bank. 128 * 1024 = 131,0722 bytes per sector. I’m storing the bootloader in Bank 1 Sector 0 and my application will be stored in sector 1 and onward.
So I added the following to encoder.py:
STM32H7_SECTOR_BASE_ADDRESS = [ 0x08000000, 0x08020000, 0x08040000, 0x08060000, 0x08080000, 0x080A0000, 0x080C0000, 0x080E0000, 0x08100000, 0x08120000, 0x08140000, 0x08160000, 0x08180000, 0x081A0000, 0x081C0000, 0x081E0000 ] STM32H7_BLOCK_SIZE = 131072 STM32H7_APPLICATION_START = 0x08020000
Then, because the file() method has been removed in Py 3, I added:
data = open(args, 'rb') data.seek(0) dataLength = len(data.read()) data.seek(0) dataList = b"" while (byte := data.read(1)): dataList += byte
Then, i basically just created another set of options for stm32h7… but used the same ‘pause’ settings as the ones used for the stm32f4.
elif options.target == 'stm32h7': for x in range(0, dataLength, STM32H7_BLOCK_SIZE): address = STM32H7_APPLICATION_START + x block = dataList[x:x+STM32H7_BLOCK_SIZE] pause = 3.5 if address in STM32H7_SECTOR_BASE_ADDRESS else 0.2 for block in encoder.code(block, STM32H7_BLOCK_SIZE, pause): if len(block): writer.append(block) blank_duration = 5.0
There were various other updates required to explicitly define certain operations as integer operations instead of floating point… I tackled this by typecasting or using floor division in a couple of places. One of the most important spots seemed to be in _encode_qpsk() method…
def _encode_qpsk(self, symbol_stream): # Updated by JJ - used floor division here ratio = self._sr // self._br * 2 # End JJ symbol_stream = numpy.array(symbol_stream) bitstream_even = 2 * self._upsample(symbol_stream % 2, ratio) - 1 # Updated by JJ - used floor division here bitstream_odd = 2 * self._upsample(symbol_stream // 2, ratio) - 1 # End JJ return bitstream_even / numpy.sqrt(2.0), bitstream_odd / numpy.sqrt(2.0)
After running the code, my .wav file seems to be formatted correctly, which is good and I’m not getting any errors:
- Chunk ID = 52/49/46/46 = ‘RIFF’ in ascii
- ChunkSize =0x009961a4 = 10,052,004 → 9816 kBytes
- Format = 57/41/56/45 = ‘WAVE’ in ascii
- Subchunk1 ID = 66/6d/74/20 = 'fmt ’ in ascii
- Subchunk 1 size = 0x00000010 (little endian) aka 16 bit
- AudioFormat = 0x0001 (little endian) aka PCM
- NumChannels = 0x0001 (little endian) aka mono
- SampleRate = 0x0000bb80 (little endian) aka 48000 Hz
- ByteRate = 48000 * 1 * 16 / 8 = 96000 = 0x00017700 (little endian)
- BlockAlign = 1 * 16 / 8 = 2 = 2 0x0002 (little endian)
- BitsPerSample = 0x0010 (little endian) = 16 bits
- Subchunk2ID = 64/61/74/61 = ‘data’ in ascii
- Subchunk2size = 0x00996180 (little endian) = 10,051,968 → 9816 kBytes
- Data = the actual data
Converting the .WAV file output data to .csv and plotting a small section of the output… things SEEM to look QPSK-ish? But the sound output is much more harsh than what I’m hearing on other Mutable releases so I feel like I’m not quite there yet.
This is where I’ve left off for now. Any advice would be much appreciated! I’m out of ideas at the moment and am going to sleep on it for now.