It appears to be a device with digital output using PDM (Pulse Density Modulation), which is the 1-bit oversampled output of a sigma-delta ADC-- it's similar to what's used in SACD. A microcontroller should be able to convert it to the more usual PCM format by digital filtering and resampling, provided it has enough processing power. Since the CS43L22 appears to take PCM data for input, you have no escape but to perform this conversion if you want to use it.
An alternative, which I believe should work, is to just output the data digitally via a GPIO, perform analog filtering (lowpass filtering at a cutoff of, say, 20 kHz), and then input it to an audio amplifier.
Structures are unsuitable for writing register maps, because a struct can have padding bytes added anywhere inside it, for alignment purposes. This depends on the compiler - you have to ensure that no padding is used (for example through a static assert).
Furthermore, it is easy to make mistakes when writing large structures that are supposed to reflect a register map, you have to get every single byte right or you'll break everything. This makes the struct vulnerable during maintenance.
I would strongly suggest you to write register maps through macros, such as:
#define PERIPH_A_DID0 (*(volatile uint32_t*)0x400FE000u))
#define PERIPH_A_DID1 (*(volatile uint32_t*)0x400FE004u))
This also has the advantage of being 100% portable to any C compiler.
Alternatively, you could do something more intricate such as this:
typedef volatile uint8_t* SCI_port;
#ifndef SCI0
#define SCI0 (&SCI0BDH)
#define SCI1 (&SCI1BDH)
#endif
#define SCIBDH(x) (*((SCI_port)x + 0x00)) /* SCI Baud Rate Register High */
#define SCIBDL(x) (*((SCI_port)x + 0x01)) /* SCI Baud Rate Register Low */
#define SCICR1(x) (*((SCI_port)x + 0x02)) /* SCI Control Register1 */
#define SCICR2(x) (*((SCI_port)x + 0x03)) /* SCI Control Register 2 */
#define SCISR1(x) (*((SCI_port)x + 0x04)) /* SCI Status Register 1 */
#define SCISR2(x) (*((SCI_port)x + 0x05)) /* SCI Status Register 2 */
#define SCIDRH(x) (*((SCI_port)x + 0x06)) /* SCI Data Register High */
#define SCIDRL(x) (*((SCI_port)x + 0x07)) /* SCI Data Register Low */
Then when writing your driver, you can do like this:
void sci_init (SCI_port port, ...)
{
SCICR1(port) = THIS | THAT;
SCICR2(port) = SOMETHING_ELSE;
...
}
This is very useful when you have many identical peripherals on the MCU, with the same registers, but only want one code to control them.
Best Answer
There are two different versions of STM32F4 headers released by ST, with some incompatibilities. The one that comes with the StdPeriph library defines 16 bit
BSRRL
andBSRRH
, that is the one you have. The other one that comes with the STM32CubeF4 library has a single 32 bitBSRR
definition, which corresponds to the reference manual.Now check the definition in your headers
BSRRL
corresponds to the low half, bits 0-15 of theBSRR
register as described in the reference manual, which sets the corresponding output bit to 1 (high).BSRRH
corresponds to the high half, bits 16-31 of theBSRR
register, which sets the corresponding output bit to 0 (low).You can use
BSRRL
instead ofBSRR
to turn a pin on, but keep in mind that the definition is only 16 bits, so you can't turn some bits on and some other pins off in a single operation using this definition, because the writes are truncated to 16 bits by the compiler.BSRRL
has the same function ofBRR
, the only difference is that the write is truncated to 16 bits by the compiler, nothing that you have to worry about unless you must count the cycles to get some timing right.