~ruther/stm32h747i-disco-usb-image-viewer

d0823eecd4dee0c7e2f3ee08534b89477526b6ad — Rutherther 5 months ago 919d35c
feat: add registers, pin, exti, usb_device skeleton
A include/exti.h => include/exti.h +22 -0
@@ 0,0 1,22 @@
#include <stdint.h>
#include <stm32h747xx.h>

#ifndef EXTI_H
#define EXTI_H

typedef struct {
  EXTI_TypeDef* exti;
  SYSCFG_TypeDef* syscfg;
} exti_t;

exti_t* exti_init(EXTI_TypeDef* exti, SYSCFG_TypeDef* syscfg);
void exti_external_interrupt(exti_t* exti, uint8_t line, uint8_t gpio);

// Only 21 positions are now supported. This is too hard for other ones.
void exti_rising_interrupt(exti_t* exti, uint8_t line);
void exti_falling_interrupt(exti_t* exti, uint8_t line);
void exti_disable_interrupt(exti_t* exti, uint8_t line);

void exti_nvic_setup(exti_t* exti, uint8_t line);

#endif // EXTI_H

A include/pin.h => include/pin.h +65 -0
@@ 0,0 1,65 @@
#include <stdlib.h>
#include <stdint.h>
#include <stm32h747xx.h>

#ifndef PIN_H
#define PIN_H

typedef struct {
  GPIO_TypeDef* gpio;
  uint8_t pin;
} pin_t;

typedef enum {
  NONE = 0,
  PULLUP = 1,
  PULLDOWN = 2,
  PULL_RESERVED = 3
} pin_pullmode_t;

typedef enum {
  INPUT,
  OUTPUT,
  ALTERNATE,
  ANALOG
} pin_mode_t;

typedef enum {
  LOW_SPEED,
  MEDIUM_SPEED,
  HIGH_SPEED,
  VERY_HIGH_SPEED
} pin_speedmode_t;

pin_t* pin_init(GPIO_TypeDef* gpio, uint8_t pin);

void pin_mode(pin_t* pin, pin_mode_t mode);
void pin_pull(pin_t* pin, pin_pullmode_t mode);
void pin_speed(pin_t* pin, pin_speedmode_t mode);

// Reads input, not output!
uint8_t pin_read(pin_t* pin);
uint8_t pin_write(pin_t* pin, uint8_t val);
void pin_toggle(pin_t* pin);
void pin_set(pin_t* pin);
void pin_reset(pin_t* pin);

void pin_into_pulldown(pin_t* pin);
void pin_into_pullup(pin_t* pin);
void pin_into_no_pull(pin_t* pin);

void pin_into_output(pin_t* pin);
void pin_into_output_pushpull(pin_t* pin);
void pin_into_output_opendrain(pin_t* pin);
void pin_into_pushpull(pin_t* pin);
void pin_into_opendrain(pin_t* pin);

void pin_into_input(pin_t* pin);
void pin_into_input_highspeed(pin_t* pin);

void pin_into_alternate(pin_t* pin, uint8_t alternate);
void pin_into_alternate_highspeed(pin_t* pin, uint8_t alternate);

void pin_into_highspeed(pin_t* pin);

#endif // PIN_H

A include/registers.h => include/registers.h +12 -0
@@ 0,0 1,12 @@
#include <stdint.h>

#ifndef REGISTERS_H
#define REGISTERS_H

void reg_set_bits_pos(volatile uint32_t *reg, uint32_t data, uint8_t pos, uint8_t mask);
void reg_set_bits(volatile uint32_t *reg, uint32_t data, uint8_t mask);
void reg_toggle_bits_pos(volatile uint32_t *reg, uint8_t pos, uint8_t mask);
void reg_toggle_bits(volatile uint32_t *reg, uint8_t mask);
uint32_t reg_read_bits_pos(volatile uint32_t *reg, uint8_t pos, uint8_t mask);

#endif // REGISTERS_H

A include/usb_device.h => include/usb_device.h +29 -0
@@ 0,0 1,29 @@
#ifndef USB_DEVICE_H
#define USB_DEVICE_H

//
#include <stm32h747xx.h>

typedef struct {
  volatile USB_OTG_GlobalTypeDef *core;
  volatile USB_OTG_DeviceTypeDef *device;
} usb_device_t;

struct usb_configuration_t;

typedef struct {

} usb_class_t;

// has configuration etc

#define USB_DEVICE_SIZE sizeof(usb_device_t)

extern usb_device_t* usb1_device;

void* usb_device_init(void* peripheral_address, usb_class_t* class, void* buffer);

void usb_device_setup(void* device);
void* usb_device_wait_for_handshake(void* device);

#endif // USB_DEVICE_H

A src/exti.c => src/exti.c +75 -0
@@ 0,0 1,75 @@
#include <stdint.h>
#include <stdlib.h>

#include "exti.h"
#include "registers.h"
#include "stm32h747xx.h"

exti_t *exti_init(EXTI_TypeDef *exti, SYSCFG_TypeDef *syscfg) {
  exti_t* exti_periph = (exti_t*)malloc(sizeof(exti_t));

  exti_periph->exti = exti;
  exti_periph->syscfg = syscfg;

  return exti_periph;
}

void exti_external_interrupt(exti_t *exti, uint8_t line, uint8_t gpio) {
  // TODOA; general
  uint8_t index = line >> 2;
  uint8_t pos = (line & 0x3) * 4;
  volatile uint32_t *exticr = exti->syscfg->EXTICR;
  reg_set_bits_pos(exticr + index, gpio, pos, 0x0F);
}

void exti_rising_interrupt(exti_t *exti, uint8_t line) {
  reg_set_bits_pos(&exti->exti->RTSR1, 1, line, 1);
  reg_set_bits_pos(&exti->exti->FTSR1, 0, line, 1);
  reg_set_bits_pos(&exti->exti->IMR1, 1, line, 1);
}

void exti_falling_interrupt(exti_t *exti, uint8_t line) {
  reg_set_bits_pos(&exti->exti->FTSR1, 1, line, 1);
  reg_set_bits_pos(&exti->exti->RTSR1, 0, line, 1);
  reg_set_bits_pos(&exti->exti->IMR1, 1, line, 1);
}

void exti_disable_interrupt(exti_t *exti, uint8_t line) {
  reg_set_bits_pos(&exti->exti->IMR1, 0, line, 1);
}

IRQn_Type exti_irq_idx(uint8_t line) {
  switch (line) {
  case 0:
    return EXTI0_IRQn;
  case 1:
    return EXTI1_IRQn;
  case 2:
    return EXTI2_IRQn;
  case 3:
    return EXTI3_IRQn;
  case 4:
    return EXTI4_IRQn;
  case 5:
  case 6:
  case 7:
  case 8:
  case 9:
    return EXTI9_5_IRQn;
  case 10:
  case 11:
  case 12:
  case 13:
  case 14:
  case 15:
    return EXTI15_10_IRQn;
  default:
    return -1;
  }
}

void exti_nvic_setup(exti_t *exti, uint8_t line) {
  IRQn_Type idx = exti_irq_idx(line);
  NVIC_SetPriority(idx, 2);
  NVIC_EnableIRQ(idx);
}

A src/pin.c => src/pin.c +78 -0
@@ 0,0 1,78 @@
#include "pin.h"
#include "registers.h"
#include <stdlib.h>

pin_t *pin_init(GPIO_TypeDef *gpio, uint8_t pin) {
  pin_t* pin_periph = (pin_t*)malloc(sizeof(pin_t));

  pin_periph->gpio = gpio;
  pin_periph->pin = pin;

  return pin_periph;
}

void pin_mode(pin_t *pin, pin_mode_t mode) {
  reg_set_bits_pos(&pin->gpio->MODER, (uint32_t)mode, pin->pin << 1, 0b11);
}
void pin_pull(pin_t *pin, pin_pullmode_t mode) {
  reg_set_bits_pos(&pin->gpio->PUPDR, (uint32_t)mode, pin->pin << 1, 0b11);
}
void pin_speed(pin_t *pin, pin_speedmode_t mode) {
  reg_set_bits_pos(&pin->gpio->OSPEEDR, (uint32_t)mode, pin->pin << 1, 0b11);
}

uint8_t pin_read(pin_t *pin) {
  reg_read_bits_pos(&pin->gpio->IDR, pin->pin, 1);
}

uint8_t pin_write(pin_t *pin, uint8_t val) {
  reg_set_bits_pos(&pin->gpio->ODR, val, pin->pin, 1);
}
void pin_toggle(pin_t *pin) {
  reg_toggle_bits_pos(&pin->gpio->ODR, pin->pin, 1);
}
void pin_set(pin_t *pin) {
  pin->gpio->ODR = 1 << pin->pin;
}
void pin_reset(pin_t *pin) {
  pin->gpio->ODR = 1 << (pin->pin + 15);
}

void pin_into_output(pin_t *pin) {
  pin_mode(pin, OUTPUT);
}
void pin_into_output_pushpull(pin_t *pin) {
  pin_into_output(pin);
  pin_into_pushpull(pin);
}
void pin_into_output_opendrain(pin_t *pin) {
  pin_into_output(pin);
  pin_into_opendrain(pin);
}

void pin_into_pushpull(pin_t *pin) {
  reg_set_bits_pos(&pin->gpio->OTYPER, 0, pin->pin, 1);
}
void pin_into_opendrain(pin_t *pin) {
  reg_set_bits_pos(&pin->gpio->OTYPER, 1, pin->pin, 1);
}

void pin_into_input(pin_t *pin) {
  pin_mode(pin, INPUT);
}
void pin_into_input_highspeed(pin_t *pin) {
  pin_into_input(pin);
  pin_into_highspeed(pin);
}

void pin_into_alternate(pin_t *pin, uint8_t alternate) {
  pin_mode(pin, ALTERNATE);
}
void pin_into_alternate_highspeed(pin_t *pin, uint8_t alternate) {
  pin_into_alternate(pin, alternate);
  pin_into_highspeed(pin);
}

void pin_into_highspeed(pin_t *pin) {
  pin_speed(pin, HIGH_SPEED);
}

A src/registers.c => src/registers.c +23 -0
@@ 0,0 1,23 @@
#include <stdint.h>

void reg_set_bits_pos(volatile uint32_t *reg, uint32_t data, uint8_t pos, uint8_t mask) {
  *reg &= ~(mask << pos);
  *reg |= (data & mask) << pos;
}

void reg_set_bits(volatile uint32_t *reg, uint32_t data, uint8_t mask) {
  *reg &= ~(mask);
  *reg |= (data & mask);
}

void reg_toggle_bits_pos(volatile uint32_t *reg, uint8_t pos, uint8_t mask) {
  *reg ^= (mask << pos);
}

void reg_toggle_bits(volatile uint32_t *reg, uint8_t mask) {
  *reg ^= mask;
}

uint32_t reg_read_bits_pos(volatile uint32_t *reg, uint8_t pos, uint8_t mask) {
  return ((*reg) >> pos) & mask;
}

A src/usb_device.c => src/usb_device.c +103 -0
@@ 0,0 1,103 @@
#include "usb_device.h"
#include <stdlib.h>
#include <stddef.h>
#include <stm32h747xx.h>

/* USB_OTG_GlobalTypeDef */

usb_device_t* usb1_device;

void* usb_device_init(void* peripheral_address, usb_class_t* class, void* buffer)
{
  if (buffer == NULL) {
    buffer = (void*)malloc(sizeof(usb_device_t));
  }

  usb_device_t* device = (usb_device_t*)buffer;

  device->core = peripheral_address;
  device->device = peripheral_address + USB_OTG_DEVICE_BASE;

  usb1_device = device;

  return device;
}

void usb_device_reset(void* device_ptr)
{
  usb_device_t* device = (usb_device_t*)device_ptr;
  while ((device->core->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
  device->core->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
  while (device->core->GRSTCTL & USB_OTG_GRSTCTL_CSRST);
  while ((device->core->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
}

void usb_device_clear_interrupts(void* device_ptr)
{
  usb_device_t* device = (usb_device_t*)device_ptr;
  device->core->GINTSTS = 0; // clear interrupts

  // for other interrupts the rx queue has to be read
}

void usb_device_setup(void* device_ptr)
{
  RCC->AHB1ENR |= RCC_AHB1ENR_USB1OTGHSEN | RCC_AHB1ENR_USB1OTGHSULPIEN;

  volatile uint32_t dummy;
  dummy = RCC->AHB1ENR;
  dummy = RCC->AHB1ENR;

  NVIC_SetPriority(OTG_FS_IRQn, 2);
  NVIC_EnableIRQ(OTG_FS_IRQn);

  // 1. core initialization
  usb_device_t* device = (usb_device_t*)device_ptr;

  RCC->AHB1ENR |= RCC_AHB1ENR_USB1OTGHSULPIEN | RCC_AHB1ENR_USB1OTGHSEN;

  /* PWR->CR3 |= PWR_CR3_USBREGEN; */
  /* while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0); */

  device->core->GCCFG |= USB_OTG_GCCFG_PWRDWN;

  device->core->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;

  // global interrupt mask
  // rx fifo non empty
  // periodic tx fifo empty level
  usb_device_clear_interrupts(device_ptr);
  device->core->GAHBCFG = USB_OTG_GAHBCFG_GINT | USB_OTG_GAHBCFG_TXFELVL | USB_OTG_GAHBCFG_HBSTLEN_2;

  // hnp capable, srp capable, otg hs timeout, usb turnaround
  // TODO: based on enumeration speed set TOCAL - fs timeout calibration
  device->core->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_ULPIEVBUSI | USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_TRDT_3 | USB_OTG_GUSBCFG_TRDT_2;

  // unmask otg interrupt mask
  device->core->GINTMSK |= USB_OTG_GINTMSK_OTGINT | USB_OTG_GINTMSK_MMISM;

  // device initialization

  // descdma, device speed, non-zero-length status out handshake, periodic frame interval
  device->device->DCFG = 0;

  // TODO device threshold control register IF DMA

  usb_device_reset(device_ptr);

  // sdis bit
  device->device->DCTL = ~(USB_OTG_DCTL_SDIS);

  // unmask interrupts usb reset, enumeration done, early suspend, usb suspend, sof
  device->core->GINTMSK |= USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_RSTDEM | USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ESUSPM | USB_OTG_GINTMSK_SOFM;

  // wait for usbrst interrupt - the reset
  while (((device->core->GINTSTS) & USB_OTG_GINTSTS_USBRST) == 0) {}

  // wait for enumdne interrupt - end of reset
  while (((device->core->GINTSTS) & USB_OTG_GINTSTS_ENUMDNE) == 0) {}
}

void otg_hs_handler(void) {

}

Do not follow this link