Skip to content

Commit

Permalink
Initial seemingly functional firmware
Browse files Browse the repository at this point in the history
  • Loading branch information
jpieper committed Mar 11, 2019
1 parent a96ba51 commit cdaff10
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 5 deletions.
2 changes: 2 additions & 0 deletions debug.gdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dir bazel-mjmech_pi3_hat
target remote localhost:3333
3 changes: 3 additions & 0 deletions fw/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ load("@com_github_ARMmbed_mbed-os//:rules.bzl", "mbed_binary")
mbed_binary(
name = "pi3_hat",
srcs = [
"millisecond_timer.h",
"pi3_hat.cc",
"stm32_serial.cc",
"stm32_serial.h",
],
)

Expand Down
66 changes: 66 additions & 0 deletions fw/millisecond_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2018-2019 Josh Pieper, [email protected].
//
// 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 "mbed.h"

namespace fw {

class MillisecondTimer {
public:
MillisecondTimer() {
__HAL_RCC_TIM2_CLK_ENABLE();

handle_.Instance = TIM2;
handle_.Init.Period = 0xFFFFFFFF;
handle_.Init.Prescaler =
(uint32_t)(SystemCoreClock / 1U / 1000000U) - 1; // 1 us tick
handle_.Init.ClockDivision = 1;
handle_.Init.CounterMode = TIM_COUNTERMODE_UP;
handle_.Init.RepetitionCounter = 0;

HAL_TIM_Base_Init(&handle_);
}

uint32_t read_ms() {
return TIM2->CNT / 1000;
}

uint32_t read_us() {
return TIM2->CNT;
}

void wait_ms(uint32_t delay_ms) {
wait_us(delay_ms * 1000);
}

void wait_us(uint32_t delay_us) {
uint32_t current = TIM2->CNT;
uint32_t elapsed = 0;
while (true) {
const uint32_t next = TIM2->CNT;
elapsed += next - current;
// We check delay_us + 1 since we don't know where in the
// current microsecond we started.
if (elapsed >= (delay_us + 1)) { return; }
current = next;
}
}

private:
TIM_HandleTypeDef handle_;
};

}
72 changes: 67 additions & 5 deletions fw/pi3_hat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,75 @@

#include "mbed.h"

#include "fw/millisecond_timer.h"
#include "fw/stm32_serial.h"

int main(void) {
DigitalOut led(PB_3);
DigitalOut led1(PB_3, 1);
DigitalOut led2(PB_4, 1);

fw::Stm32Serial master_serial{[]() {
fw::Stm32Serial::Options options;
options.tx = PA_9;
options.rx = PA_10;
options.baud_rate = 3000000;
return options;
}()};
auto* const master_uart = master_serial.uart();

master_uart->CR1 &= ~USART_CR1_UE;
master_uart->CR1 |= USART_CR1_TE | USART_CR1_RE;
// master_uart->CR3 |= USART_CR3_OVRDIS;
master_uart->CR1 |= USART_CR1_UE;

fw::Stm32Serial slave_serial{[]() {
fw::Stm32Serial::Options options;
options.tx = PA_2;
options.rx = PA_3;
options.baud_rate = 3000000;
return options;
}()};
auto* const slave_uart = slave_serial.uart();

slave_uart->CR1 &= ~USART_CR1_UE;
slave_uart->CR3 |= USART_CR3_DEM;
// slave_uart->CR3 |= USART_CR3_OVRDIS;
slave_uart->CR1 |= USART_CR1_TE | USART_CR1_RE;
slave_uart->CR1 =
(slave_uart->CR1 & ~USART_CR1_DEAT) | (6 << USART_CR1_DEAT_Pos);
slave_uart->CR1 =
(slave_uart->CR1 & ~USART_CR1_DEDT) | (6 << USART_CR1_DEDT_Pos);
slave_uart->CR1 |= USART_CR1_UE;

pinmap_pinout(PA_1, PinMap_UART_RTS);

fw::MillisecondTimer timer;
uint32_t flash_count = 0;

// We don't want *any* interrupts while we are running. Our inner
// loop runs at about 1us per iteration, and any glitches can
// cause a receiver overrun.
__disable_irq();

while (true) {
led.write(1);
wait_us(1000000);
led.write(0);
wait_us(1000000);
if (master_uart->ISR & USART_ISR_RXNE) {
const uint8_t value = master_uart->RDR;
// Wait for any previous write to complete.
while ((slave_uart->ISR & USART_ISR_TXE) == 0);
slave_uart->TDR = value;
}
if (slave_uart->ISR & USART_ISR_RXNE) {
const int value = slave_uart->RDR;
while ((master_uart->ISR & USART_ISR_TXE) == 0);
master_uart->TDR = value;
}
if (true) {
const uint32_t time_s = timer.read_us() >> 20;
if (time_s != flash_count) {
flash_count = time_s;
led1.write(!led1.read());
}
}
led2.write(!led2.read());
}
}
99 changes: 99 additions & 0 deletions fw/stm32_serial.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2018-2019 Josh Pieper, [email protected].
//
// 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.

#include "fw/stm32_serial.h"

namespace fw {

namespace {
int32_t GetMax16OversamplingBaud(UARTName uart) {
switch (uart) {
case UART_1:
return 5620000;
case UART_2:
return 2810000;
}
mbed_die();
return 0;
}

void EnableClock(UARTName uart) {
if (uart == UART_1) {
__HAL_RCC_USART1_CLK_ENABLE();
} else if (uart == UART_2) {
__HAL_RCC_USART2_CLK_ENABLE();
} else {
mbed_die();
}
#if defined(UART7_BASE) || defined(USART7_BASE)
#error "Need to handle more uarts"
#endif
}

}

Stm32Serial::Stm32Serial(const Options& options) {
uart_= [&]() {
const auto uart_tx = static_cast<UARTName>(
pinmap_peripheral(options.tx, PinMap_UART_TX));
const auto uart_rx = static_cast<UARTName>(
pinmap_peripheral(options.rx, PinMap_UART_RX));
return reinterpret_cast<USART_TypeDef*>(pinmap_merge(uart_tx, uart_rx));
}();
if (uart_ == nullptr) {
mbed_die();
}

// Reset and enable clock.
EnableClock(uart_name());

// Configure pins for alternate functions.
pinmap_pinout(options.tx, PinMap_UART_TX);
pinmap_pinout(options.rx, PinMap_UART_RX);
if (options.tx != NC) {
pin_mode(options.tx, PullUp);
}
if (options.rx != NC) {
pin_mode(options.rx, PullUp);
}

// Then configure the UART itself.
UART_HandleTypeDef huart{};

huart.Instance = uart_;
huart.Init.BaudRate = options.baud_rate;
huart.Init.WordLength = 8;
huart.Init.StopBits = 1;
huart.Init.Parity = UART_PARITY_NONE;
huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;

const int32_t max_16oversampling_baud =
GetMax16OversamplingBaud(uart_name());
huart.Init.OverSampling =
(options.baud_rate > max_16oversampling_baud ?
UART_OVERSAMPLING_8 :
UART_OVERSAMPLING_16);

if (options.tx == NC) {
huart.Init.Mode = UART_MODE_RX;
} else if (options.rx == NC) {
huart.Init.Mode = UART_MODE_TX;
} else {
huart.Init.Mode = UART_MODE_TX_RX;
}

HAL_UART_Init(&huart);
}

}
51 changes: 51 additions & 0 deletions fw/stm32_serial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2018 Josh Pieper, [email protected].
//
// 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 "mbed.h"
#include "serial_api_hal.h"
#include "PeripheralPins.h"

namespace fw {

/// When constructed, this will configure the given serial port,
/// including marking the relevant pins as alternate function.
///
/// NOTE: Unlike the Mbed RawSerial class, this will use 8X
/// oversampling when necessary to achieve higher baud rates.
class Stm32Serial {
public:
struct Options {
PinName tx = NC;
PinName rx = NC;

int baud_rate = 115200;
};

Stm32Serial(const Options&);

UARTName uart_name() const {
return static_cast<UARTName>(reinterpret_cast<uint32_t>(uart_));
}

USART_TypeDef* uart() {
return uart_;
}

private:
USART_TypeDef* uart_;
};

}
6 changes: 6 additions & 0 deletions run_openocd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

openocd \
-f /usr/share/openocd/scripts/interface/stlink-v2.cfg \
-f /usr/share/openocd/scripts/target/stm32f0x_stlink.cfg \
-c init -c "reset_config none separate; reset init"
6 changes: 6 additions & 0 deletions run_openocd_noreset.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

openocd \
-f /usr/share/openocd/scripts/interface/stlink-v2.cfg \
-f /usr/share/openocd/scripts/target/stm32f0x_stlink.cfg \
-c "reset_config none separate"

0 comments on commit cdaff10

Please sign in to comment.