Skip to content

Commit

Permalink
✨ Add stm32_generic::spi & stm32f1::spi
Browse files Browse the repository at this point in the history
- Migrate `stm32f411` to use `stm32_generic::spi`
- Build all unit test files
- Migrate unit tests to use the automatic boost::ut::suite
- cortex_m tests did not need ordering so have been migrated to
  boost::ut::suite.

Resolves #10
  • Loading branch information
kammce committed Aug 17, 2024
1 parent b5f3f4e commit 439bb4b
Show file tree
Hide file tree
Showing 30 changed files with 834 additions and 442 deletions.
46 changes: 24 additions & 22 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ libhal_test_and_make_library(
src/lpc40/stream_dac.cpp
src/lpc40/uart.cpp

# stm32_generic
src/stm32_generic/spi.cpp

# stm32f1
src/stm32f1/can_reg.hpp
src/stm32f1/can.cpp
Expand All @@ -59,6 +62,7 @@ libhal_test_and_make_library(
src/stm32f1/rcc_reg.hpp
src/stm32f1/uart_reg.hpp
src/stm32f1/uart.cpp
src/stm32f1/spi.cpp

# stm32f411
src/stm32f411/input_pin.cpp
Expand All @@ -71,35 +75,33 @@ libhal_test_and_make_library(
src/stm32f40/output_pin.cpp

TEST_SOURCES
# cortex_m
tests/dwt_counter.test.cpp
tests/interrupt.test.cpp
tests/main.test.cpp
tests/systick_timer.test.cpp

# # lpc40
# tests/lpc40/adc.test.cpp
# tests/lpc40/can.test.cpp
# tests/lpc40/helper.hpp
# tests/lpc40/i2c.test.cpp
# tests/lpc40/input_pin.test.cpp
# tests/lpc40/interrupt_pin.test.cpp
# tests/lpc40/main.test.cpp
# tests/lpc40/output_pin.test.cpp
# tests/lpc40/pwm.test.cpp
# tests/lpc40/spi.test.cpp
# tests/lpc40/stream_dac.test.cpp
# tests/lpc40/uart.test.cpp

# # stm32f1
# tests/stm32f1/can.test.cpp
# tests/stm32f1/helper.hpp
# tests/stm32f1/main.test.cpp
# tests/stm32f1/output_pin.test.cpp
# tests/stm32f1/uart.test.cpp
# lpc40
tests/lpc40/adc.test.cpp
tests/lpc40/can.test.cpp
tests/lpc40/i2c.test.cpp
tests/lpc40/input_pin.test.cpp
tests/lpc40/interrupt_pin.test.cpp
tests/lpc40/output_pin.test.cpp
tests/lpc40/pwm.test.cpp
tests/lpc40/spi.test.cpp
tests/lpc40/stream_dac.test.cpp
tests/lpc40/uart.test.cpp

# # stm32f411
# stm32f1
tests/stm32f1/can.test.cpp
tests/stm32f1/output_pin.test.cpp
tests/stm32f1/uart.test.cpp
tests/stm32f1/spi.test.cpp

# # stm32f40
# stm32f411
tests/stm32f411/output_pin.test.cpp
tests/stm32f411/spi.test.cpp

PACKAGES
libhal
Expand Down
11 changes: 2 additions & 9 deletions demos/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,10 @@ resource_list resources{};

int main()
{
try {
resources = initialize_platform();
} catch (...) {
while (true) {
// halt here and wait for a debugger to connect
continue;
}
}

hal::set_terminate(terminate_handler);

resources = initialize_platform();

try {
application(resources);
} catch (std::bad_optional_access const& e) {
Expand Down
34 changes: 26 additions & 8 deletions demos/platforms/stm32f103c8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
#include <libhal-arm-mcu/stm32f1/constants.hpp>
#include <libhal-arm-mcu/stm32f1/input_pin.hpp>
#include <libhal-arm-mcu/stm32f1/output_pin.hpp>
#include <libhal-arm-mcu/stm32f1/spi.hpp>
#include <libhal-arm-mcu/stm32f1/uart.hpp>
#include <libhal-arm-mcu/system_control.hpp>
#include <libhal-soft/bit_bang_i2c.hpp>
#include <libhal-soft/inert_drivers/inert_adc.hpp>

#include <libhal/output_pin.hpp>
#include <libhal/units.hpp>
#include <resource_list.hpp>

resource_list initialize_platform()
Expand All @@ -46,16 +49,29 @@ resource_list initialize_platform()
// pin G0 on the STM micromod is port B, pin 4
static hal::stm32f1::input_pin input_pin('B', 4);

// TODO(kammce): change this before submission

static hal::stm32f1::output_pin sda_output_pin('B', 7);
static hal::stm32f1::output_pin scl_output_pin('B', 6);
static hal::bit_bang_i2c bit_bang_i2c(
hal::bit_bang_i2c::pins{
.sda = &sda_output_pin,
.scl = &scl_output_pin,
},
steady_clock);

sda_output_pin.configure({
.resistor = hal::pin_resistor::pull_up,
.open_drain = true,
});
scl_output_pin.configure({
.resistor = hal::pin_resistor::pull_up,
.open_drain = true,
});
static hal::bit_bang_i2c::pins bit_bang_pins{
.sda = &sda_output_pin,
.scl = &scl_output_pin,
};
static hal::bit_bang_i2c bit_bang_i2c(bit_bang_pins, steady_clock);
static hal::stm32f1::output_pin spi_chip_select('A', 4);
static hal::stm32f1::spi spi1(hal::bus<2>,
{
.clock_rate = 250.0_kHz,
.clock_polarity = false,
.clock_phase = false,
});

return {
.reset = []() { hal::cortex_m::reset(); },
Expand All @@ -66,5 +82,7 @@ resource_list initialize_platform()
.adc = &adc,
.input_pin = &input_pin,
.i2c = &bit_bang_i2c,
.spi = &spi1,
.spi_chip_select = &spi_chip_select,
};
}
105 changes: 105 additions & 0 deletions include/libhal-arm-mcu/stm32_generic/spi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <span>

#include <libhal/initializers.hpp>
#include <libhal/spi.hpp>
#include <libhal/units.hpp>

namespace hal::stm32_generic {
/**
* @brief A generic spi implementation for all stm32f series MCUs
*
* This class is meant to only be used by platform libraries or drivers aiming
* to be platform libraries for stm32f devices. As an application develop,
* prefer to use the platform specific drivers instead as they handle all of the
* initialization for you.
*
*/
class spi
{
public:
/**
* @brief Construct a new spi object
*
* Care must be taken when constructing this object. The constructor does not
* and cannot power on the spi peripheral. Accessing the peripheral's
* registers without it be powered on (or provided a clock), will result in a
* memory fault as the peripheral cannot ACK the CPU when it attempts to
* access the peripheral's registers. The power management system for each
* peripheral across the stm32 series of MCUs is different, meaning its not
* something that can efficiently be manged by this generic driver.
*
* After constructing this object, in order to use this driver the program
* must:
*
* 1. Configure pins to be controlled by the spi peripheral pointed to by the
* `p_peripheral_address` input parameter.
* 2. Power on the appropriate spi peripheral
* 3. Execute the `configure()` function with the appropriate peripheral
* frequency.
*
* Performing these in this order will properly initialize the spi driver and
* allow the usage of the `transfer()` API. Failing to execute these steps in
* this order will result in UB.
*
* NOTE: why does this driver get away with breaking the rule about
* construction means initialization? Because its constructor is marked unsafe
* meaning care needs to be taken when using this.
*
* @param p_peripheral_address - starting address of the spi peripheral
*/
spi(hal::unsafe, void* p_peripheral_address);

spi(spi& p_other) = delete;
spi& operator=(spi& p_other) = delete;
spi(spi&& p_other) noexcept = delete;
spi& operator=(spi&& p_other) noexcept = delete;
~spi();

/**
* @brief Configure the SPI peripheral
*
* Because each stm32f series MCU has its own unique clock tree, there is no
* single, simple and space efficient may to determine the system's spi clock
* speed. So the caller must supply the operating frequency of the spi
* peripheral for this to work. This API is meant to be called by platform
* specific spi drivers that have the necessary context and library apis to
* retrieve the spi peripheral's clock rate.
*
* @param p_settings - spi settings
* @param p_peripheral_clock_speed - peripheral's operating clock rate
*/
void configure(hal::spi::settings const& p_settings,
hal::hertz p_peripheral_clock_speed);

/**
* @brief Perform a transfer operation as defined in `hal::spi::transfer`
*
* @param p_data_out - outgoing data
* @param p_data_in - incoming data
* @param p_filler - output filler bytes if the outgoing data runs out before
* the incoming data.
*/
void transfer(std::span<hal::byte const> p_data_out,
std::span<hal::byte> p_data_in,
hal::byte p_filler);

private:
void* m_peripheral_address;
};
} // namespace hal::stm32_generic
14 changes: 14 additions & 0 deletions include/libhal-arm-mcu/stm32f1/can.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal/can.hpp>
Expand Down
14 changes: 14 additions & 0 deletions include/libhal-arm-mcu/stm32f1/dma.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cstdint>
Expand Down
14 changes: 14 additions & 0 deletions include/libhal-arm-mcu/stm32f1/interrupt.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

namespace hal::stm32f1 {
Expand Down
57 changes: 57 additions & 0 deletions include/libhal-arm-mcu/stm32f1/spi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal-arm-mcu/stm32_generic/spi.hpp>
#include <libhal/initializers.hpp>
#include <libhal/spi.hpp>

#include "constants.hpp"

namespace hal::stm32f1 {
class spi : public hal::spi
{
public:
/**
* @brief Construct a new spi driver
*
* @param p_bus - spi bus number from 1 to 3
* @param p_settings - initial spi settings
*/
spi(hal::bus_param auto p_bus, spi::settings const& p_settings = {})
: spi(p_bus(), p_settings)
{
static_assert(1 <= p_bus() and p_bus() <= 3,
"stm32f1 only supports ports from 1 to 3");
}

spi(spi& p_other) = delete;
spi& operator=(spi& p_other) = delete;
spi(spi&& p_other) noexcept = delete;
spi& operator=(spi&& p_other) noexcept = delete;
~spi();

private:
spi(std::uint8_t p_bus_number, spi::settings const& p_settings = {});

void driver_configure(settings const& p_settings) override;
void driver_transfer(std::span<hal::byte const> p_data_out,
std::span<hal::byte> p_data_in,
hal::byte p_filler) override;

peripheral m_peripheral_id;
stm32_generic::spi m_spi_driver;
};
} // namespace hal::stm32f1
14 changes: 14 additions & 0 deletions include/libhal-arm-mcu/stm32f1/uart.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cstdint>
Expand Down
Loading

0 comments on commit 439bb4b

Please sign in to comment.