Skip to content
Snippets Groups Projects
Commit 1fd71c07 authored by Christian Spangler's avatar Christian Spangler
Browse files

I finally fixed my Git repo

parent 35114c90
No related branches found
No related tags found
No related merge requests found
Showing
with 17775 additions and 0 deletions
firmware/build
*.aux *.aux
*.log *.log
*.nav *.nav
......
#include <math.h>
#include <stdio.h>
#include <cyg/hal/hal_arch.h>
#include <libopencm3/cm3/sync.h>
#include "axis.h"
#include "motor.h"
#include "ezs_io.h"
static int16_t roundSteps(double x) {
return floor(x+0.5);
}
void setAxisValues_M5(axis* axis, motor* motorA, motor* motorB) {
// pitch: mm per rotation of the leadscrew
double pitch = 0.8;
axis->motorA = motorA;
axis->motorB = motorB;
axis->lastPosMm = 0;
axis->stepsPerMm = (axis->motorA->stepsPerRevo * axis->motorA->gearRatio) / pitch;
axis->mmPerStep = 1.0 / axis->stepsPerMm;
axis->maxMmPerMin = 20000 * axis->mmPerStep;
axis->isReversed = false;
}
void setAxisValues_T25(axis* axis, motor* motorA, motor* motorB, uint8_t teeth) {
// pitch: distance between two tooth centers on the timing belt in mm
// teeth: number of teeth on the pulley attached to the motor shaft
double pitch = 2.5;
axis->motorA = motorA;
axis->motorB = motorB;
axis->lastPosMm = 0;
axis->stepsPerMm = (axis->motorA->stepsPerRevo * axis->motorA->gearRatio) / (pitch * teeth);
axis->mmPerStep = 1.0 / axis->stepsPerMm;
axis->isReversed = false;
}
void homeAxis(axis* axis) {
int8_t one = -1;
if (axis->isReversed) one = -1;
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 0) {
setMotorMotion(axis->motorA, -one, 1);
updateMotor(axis->motorA);
if (axis->motorB != NULL) {
setMotorMotion(axis->motorB, -one, 1);
updateMotor(axis->motorB);
}
ezs_delay_us(1e3);
}
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 1) {
setMotorMotion(axis->motorA, one, 1);
updateMotor(axis->motorA);
if (axis->motorB != NULL) {
setMotorMotion(axis->motorB, one, 1);
updateMotor(axis->motorB);
}
ezs_delay_us(1e5);
}
axis->lastPosMm = 0;
}
void setAxisTarget(axis* axis, double targetPosMm, double speed) {
mutex_lock(&(axis->lock));
if (axis->stepsPerMm == 0) ezs_printf("AXIS ERROR: attempting to set axis target while uninitialized");
int32_t stepsToMove = roundSteps((targetPosMm - axis->lastPosMm) * axis->stepsPerMm);
if (axis->isReversed) stepsToMove = -stepsToMove;
uint16_t stepsPerSec = (speed / 60) / axis->mmPerStep;
setMotorMotion(axis->motorA, stepsToMove, stepsPerSec);
if (axis->motorB != NULL) setMotorMotion(axis->motorB, stepsToMove, stepsPerSec);
axis->lastPosMm = targetPosMm;
mutex_unlock(&(axis->lock));
}
uint32_t updateAxis(axis* axis) {
mutex_lock(&(axis->lock));
uint32_t ret = updateMotor(axis->motorA);
if (axis->motorB != NULL) updateMotor(axis->motorB);
mutex_unlock(&(axis->lock));
return ret;
}
bool axisIsFinished(axis* axis) {
return (axis->motorA->stepsLeft) == 0;
}
Project(3DPrinter)
cmake_minimum_required(VERSION 2.8)
#include CMAKE-Modules from base directory
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}")
INCLUDE(EZS)
add_definitions("-D EZS_DUMB_SERIAL")
include_directories(${PROJECT_SOURCE_DIR}/libDIY/drivers/include)
include_directories(${PROJECT_SOURCE_DIR}/libDIY/include)
set(LIBEZS_SOURCES
# libEZS/src/ezs_tracer.cpp
libEZS/drivers/${EZS_ARCH}/ezs_gpio.c
libEZS/drivers/${EZS_ARCH}/ezs_dac.cpp
libEZS/drivers/${EZS_ARCH}/ezs_serial.cpp
libEZS/drivers/${EZS_ARCH}/ezs_counter.cpp
libEZS/src/ezs_delay.c
)
set(LIBDIY_SOURCES
libDIY/drivers/src/diy_adc.c
libDIY/drivers/src/diy_gpio.c
libDIY/drivers/src/diy_tim.c
libDIY/drivers/src/diy_int.c
)
SET(SRC_LIST
gcode.c
gcbuf.c
axis.c
motor.c
hello.c
${LIBEZS_SOURCES}
${LIBDIY_SOURCES}
)
set(TGT "app")
ECOS_ADD_EXECUTABLE(${TGT} ${SRC_LIST})
This diff is collapsed.
if(POLICY CMP0037)
cmake_policy(SET CMP0037 OLD)
endif()
# first check that ecosconfig is available
FIND_PROGRAM(ECOSCONFIG_EXECUTABLE NAMES ecosconfig)
IF("$ENV{EZS_BASE}" STREQUAL "")
MESSAGE(FATAL_ERROR "EZS_BASE not set. Did you run 'source ../ecosenv.sh'?")
ELSE()
message(STATUS "EZS_BASE: $ENV{EZS_BASE}")
IF(NOT IS_DIRECTORY "$ENV{EZS_BASE}")
MESSAGE(FATAL_ERROR "EZS_BASE set but not a directory. Check your settings in ../ecosenv.sh and your installation'?")
ENDIF()
IF(NOT IS_DIRECTORY "$ENV{EZS_CMAKE_MODULE_DIR}")
MESSAGE(FATAL_ERROR "EZS_CMAKE_MODULE_DIR is not a directory. Check your settings in ../ecosenv.sh and your installation'?")
ENDIF()
MESSAGE(STATUS "USING $ENV{EZS_BASE}")
MESSAGE(STATUS "USING $ENV{EZS_CMAKE_MODULE_DIR} as cmake module path")
set(CMAKE_MODULE_PATH "$ENV{EZS_CMAKE_MODULE_DIR}" ${CMAKE_MODULE_PATH})
set(EZS_TOOLS_DIR "$ENV{EZS_CMAKE_MODULE_DIR}")
MESSAGE(STATUS "USING ${EZS_TOOLS_DIR} as tools path")
ENDIF("$ENV{EZS_BASE}" STREQUAL "")
IF(NOT ECOSCONFIG_EXECUTABLE)
MESSAGE(FATAL_ERROR "ecosconfig was not found. Do you have a valid ecos repository?")
ENDIF(NOT ECOSCONFIG_EXECUTABLE)
IF("$ENV{EZS_LIBOPENCM3_DIR}" STREQUAL "")
MESSAGE(WARNING "OPENCM3_PATH not set. Did you run 'source ../ecosenv.sh'")
ELSE()
set(OPENCM3_PATH $ENV{EZS_LIBOPENCM3_DIR})
ENDIF()
set(EZS_CPU_FLAGS "-mcpu=cortex-m3 -mthumb")
add_definitions( "-D STM32F4")
INCLUDE(EZSconvenience)
INCLUDE(ezs_ecos_stm32)
set(EZS_ARCH stm32f4)
include_directories(${OPENCM3_PATH}/include)
ECOS_EZS_ADDLIB("${OPENCM3_PATH}/lib/libopencm3_stm32f4.a")
include_directories(${PROJECT_SOURCE_DIR}/libEZS/include)
FIND_PROGRAM(MELD_EXECUTABLE NAMES meld)
IF(MELD_EXECUTABLE)
add_custom_target(diff
COMMAND ${MELD_EXECUTABLE} "/proj/i4ezs/vorgaben/${CMAKE_PROJECT_NAME}/" "${PROJECT_SOURCE_DIR}"
COMMENT "Invoking diff")
ENDIF()
#include <math.h>
#include <stdio.h>
#include <cyg/hal/hal_arch.h>
#include <libopencm3/cm3/sync.h>
#include "axis.h"
#include "motor.h"
#include "ezs_io.h"
#include "ezs_delay.h"
static int32_t roundSteps(double x) {
return floor(x+0.5);
}
void setAxisValues_extruderBolt(axis* axis, motor* motor) {
// pitch: mm per rotation of the bolt
// gearRatio: from stepper motor to bolt
double pitch = 20.3;
uint8_t gearRatio = 4;
axis->motor = motor;
axis->lastPosMm = 0;
axis->stepsPerMm = (axis->motor->stepsPerRevo * axis->motor->gearRatio * gearRatio) / pitch;
axis->mmPerStep = 1.0 / axis->stepsPerMm;
axis->isReversed = false;
axis->isRelative = true;
}
void setAxisValues_M5(axis* axis, motor* motor) {
// pitch: mm per rotation of the leadscrew
double pitch = 0.8;
axis->motor = motor;
axis->lastPosMm = 0;
axis->stepsPerMm = (axis->motor->stepsPerRevo * axis->motor->gearRatio) / pitch;
axis->mmPerStep = 1.0 / axis->stepsPerMm;
axis->isReversed = false;
axis->isRelative = false;
}
void setAxisValues_T25(axis* axis, motor* motor, uint8_t teeth) {
// pitch: distance between two tooth centers on the timing belt in mm
// teeth: number of teeth on the pulley attached to the motor shaft
double pitch = 2.5;
axis->motor = motor;
axis->lastPosMm = 0;
axis->stepsPerMm = (axis->motor->stepsPerRevo * axis->motor->gearRatio) / (pitch * teeth);
axis->mmPerStep = 1.0 / axis->stepsPerMm;
axis->isReversed = false;
axis->isRelative = false;
}
void homeAxis(axis* axis) {
int8_t one = 1;
if (axis->isReversed) one = -1;
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 0) {
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 0) {
setMotorMotion(axis->motor, -one, 1);
updateMotor(axis->motor);
axis->totalSteps--;
ezs_delay_us(2e3);
}
ezs_delay_us(5e5);
}
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 1) {
while (diy_gpio_read_pin(axis->endstopPort, axis->endstopPin) == 1) {
setMotorMotion(axis->motor, one, 1);
updateMotor(axis->motor);
axis->totalSteps++;
ezs_delay_us(1e4);
}
ezs_delay_us(5e5);
}
axis->lastHomeRest = axis->totalSteps;
axis->totalSteps = 0;
axis->lastPosMm = axis->homePos;
}
void setAxisTarget(axis* axis, double targetPosMm, double speed) {
mutex_lock(&(axis->lock));
if (axis->stepsPerMm == 0) ezs_printf("!! AXIS ERROR: attempting to set axis target while uninitialized\n");
int32_t stepsToMove = roundSteps((targetPosMm - axis->lastPosMm) * axis->stepsPerMm);
axis->totalSteps += stepsToMove;
if (axis->isReversed) stepsToMove = -stepsToMove;
uint16_t stepsPerSec = (speed / 60) / axis->mmPerStep;
setMotorMotion(axis->motor, stepsToMove, stepsPerSec);
if (!axis->isRelative) axis->lastPosMm = targetPosMm;
mutex_unlock(&(axis->lock));
}
uint32_t updateAxis(axis* axis) {
mutex_lock(&(axis->lock));
uint32_t ret = updateMotor(axis->motor);
mutex_unlock(&(axis->lock));
return ret;
}
bool axisIsFinished(axis* axis) {
return (axis->motor->stepsLeft) == 0;
}
#ifndef HEADER_AXIS
#define HEADER_AXIS
#include <stdint.h>
#include <cyg/hal/hal_arch.h>
#include <libopencm3/cm3/sync.h>
#include "motor.h"
typedef struct {
motor* motor;
bool isReversed;
bool isRelative;
mutex_t lock;
double homePos;
double volatile lastPosMm;
double stepsPerMm;
double mmPerStep;
double maxMmPerMin;
uint32_t endstopPort;
uint16_t endstopPin;
int totalSteps;
int lastHomeRest;
} axis;
// Sets default values for timing belts and leadscrews used in the ToyRep
void setAxisValues_M5(axis* axis, motor* motor);
void setAxisValues_T25(axis* axis, motor* motor, uint8_t teeth);
void setAxisValues_extruderBolt(axis* axis, motor* motor);
// Home axis and set lastPostMm to 0
void homeAxis(axis* axis);
// Starts a move towards targetPos with speed in mm/minute
void setAxisTarget(axis* axis, double targetPosMm, double speed);
// Returns time for which the axis thread should wait
uint32_t updateAxis(axis* axis);
// Returns whether the axis has reached it's destination
bool axisIsFinished(axis* axis);
#endif
This diff is collapsed.
#!/usr/bin/env bash
I4EZS_USER_CONFIG="${HOME}/.config/i4ezs/i4ezs-ecosenv-stm32.sh"
# allow user override
if [[ -f "$I4EZS_USER_CONFIG" ]]; then
source "$I4EZS_USER_CONFIG"
elif [ -e ~/i4ezs-ecosenv-stm32.sh ]; then
echo "WARNING: Found old i4ezs config file at ~/i4ezs-ecosenv-stm32.sh. Please migrate to $I4EZS_USER_CONFIG."
source ~/i4ezs-ecosenv-stm32.sh
else
EZS_BASE=/proj/i4ezs/stm32/
fi
# Ensure that EZS_BASE is exported.
export EZS_BASE
#################### NO CHANGES BELOW SHOULD BE NEEDED ####################
EZS_UID=$$ ; export EZS_UID
EZS_COMPILER_DIR=$EZS_BASE/gcc-arm-none-eabi ; export EZS_COMPILER_DIR
EZS_TOOLS_DIR=$EZS_BASE/tools; export EZS_TOOLS_DIR
EZS_CMAKE_MODULE_DIR=$EZS_BASE/tools ; export EZS_CMAKE_MODULE_DIR
EZS_LIBOPENCM3_DIR=$EZS_BASE/libopencm3 ; export EZS_LIBOPENCM3_DIR
ECOS_BASE_DIR=$EZS_BASE/ecos
ECOS_REPOSITORY=$ECOS_BASE_DIR/packages ; export ECOS_REPOSITORY
PATH=$EZS_TOOLS_DIR:$EZS_COMPILER_DIR/bin:$PATH; export PATH
#include "gcbuf.h"
#include <stdint.h>
#include <stdlib.h>
#include <cyg/hal/hal_arch.h>
#include <libopencm3/cm3/sync.h>
int initBuffer(gcbuf* buf, gcode* array, uint16_t size) {
if (size == 0) return ERR_BUFFER_INV_SIZE;
buf->size = size;
buf->array = array;
buf->arrayEnd = buf->array + size;
buf->count = 0;
buf->nextToRead = buf->array;
buf->nextToWrite = buf->array;
return 0;
}
gcode* readIntoBuffer(gcbuf* buf, char string[]) {
while (1) {
mutex_lock(&(buf->lock));
if (buf->count < buf->size) {
gcode* ret = buf->nextToWrite;
readGcode(buf->nextToWrite, string);
(buf->nextToWrite)++;
(buf->count)++;
if (buf->nextToWrite >= buf->arrayEnd) buf->nextToWrite = buf->array;
mutex_unlock(&(buf->lock));
return ret;
}
mutex_unlock(&(buf->lock));
}
}
gcode* readFromBuffer(gcbuf* buf) {
while (1) {
mutex_lock(&(buf->lock));
if (buf->count > 0) {
gcode* ret = buf->nextToRead;
(buf->nextToRead)++;
(buf->count)--;
if (buf->nextToRead >= buf->arrayEnd) buf->nextToRead = buf->array;
mutex_unlock(&(buf->lock));
return ret;
}
mutex_unlock(&(buf->lock));
}
}
#ifndef HEADER_BUFFER
#define HEADER_BUFFER
#include <stdint.h>
#include <cyg/hal/hal_arch.h>
#include <libopencm3/cm3/sync.h>
#include "gcode.h"
typedef struct {
uint16_t size;
gcode* array;
gcode* arrayEnd;
mutex_t lock;
uint16_t volatile count;
gcode* volatile nextToRead;
gcode* volatile nextToWrite;
} gcbuf;
// Buffers must not have size 0
#define ERR_BUFFER_INV_SIZE 1
// Initializes a buffer on memory at array, so it can manage `size` gcodes
// Returns 0 on success, an error code otherwise
int initBuffer(gcbuf* buf, gcode* array, uint16_t size);
// Use readGcode from gcode.c to fill the first available gcode with new info. Blocks if full until a gcode is available
gcode* readIntoBuffer(gcbuf* buf, char string[]);
// Get a gcode from the buffer. Blocks if empty until a gcode is available
gcode* readFromBuffer(gcbuf* buf);
#endif
#include "gcode.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
int readIntValueFromString(char* string) {
int ret = 0;
bool minus = *string == '-';
if (minus) string++;
while (*string != 0) ret = ret * 10 + (*(string++) - '0');
return minus ? -ret : ret;
}
double readDoubleValueFromString(char* string) {
double ret = 0;
uint32_t decimalDiv = 0;
bool minus = *string == '-';
if (minus) string++;
while (*string != 0) {
if (*string == '.') {
decimalDiv = 1;
string++;
} else {
ret = ret * 10 + (*(string++) - '0');
decimalDiv *= 10;
}
}
if (decimalDiv > 1) ret /= decimalDiv;
return minus ? -ret : ret;
}
int readGcode(gcode* gc, char string[]) {
// TODO Mcodes and Line numbers and checksums
gc->operationId = 0;
gc->paramCount = 0;
char* hasIgnoreChar = strchr(string, ';');
if (hasIgnoreChar == NULL) hasIgnoreChar = strchr(string, '\n');
if (hasIgnoreChar != NULL) *hasIgnoreChar = 0;
char* block = strtok(string, " ");
gc->operationCategory = *block;
int operationId = readIntValueFromString(block+1);
if (operationId < 0 || operationId > 999) return ERR_GCODE_OP_INV;
gc->operationId = operationId;
while ((block = strtok(NULL, " ")) != NULL) {
gc->paramKeys[gc->paramCount] = *block;
gc->paramValues[gc->paramCount] = readDoubleValueFromString(block+1);
(gc->paramCount)++;
}
return 0;
}
double* getGcodeParam(gcode* gc, char key) {
uint8_t i = 0;
while (i < gc->paramCount) {
if (gc->paramKeys[i] == key) return (double*) &(gc->paramValues[i]);
i++;
}
return NULL;
}
#ifndef HEADER_GCODE
#define HEADER_GCODE
#include <stdint.h>
typedef struct {
char volatile operationCategory;
uint16_t volatile operationId;
uint8_t volatile paramCount;
char volatile paramKeys[16];
double volatile paramValues[16];
} gcode;
// Gcodes must start with G
#define ERR_GCODE_NO_G 1
// Gcode operation ID negative or too high (0 to 999)
#define ERR_GCODE_OP_INV 2
// Reads a gcode from a string, can be finished by a newline. This does not check whether the gcode is semantically valid, only syntactically
// Returns 0 on success, or an error code as defined above otherwise
int readGcode(gcode* gc, char string[]);
// Get a pointer to the parameter saved under the given key in a gcode, or NULL if it was not specified
double* getGcodeParam(gcode* gc, char key);
#endif
This diff is collapsed.
#ifndef DIY_ADC_H_INCLUDED
#define DIY_ADC_H_INCLUDED
/* When using with the STM32F411E-DISCO the pins/channels:
* PA0/0
* PA4/4
* PA5/5
* PA6/6
* PA7/7
* PC0/11
* PC3/13
* PC4/14
* may already be used or are not available due to other peripherals.
* Pins/channels:
* PA1/1
* PA2/2
* PA3/3
* PB0/8
* PB1/9
* PC1/11
* PC2/12
* PC5/15
* should be available.
* Channel 16 and 17 are internal channels. Channel 18 is only for V_Bat.
*/
/*! \brief Structure to configure the ADC. Use the ADC define from libDIY/drivers/
* include/diy_adc.h for the adc value and sample_time. Use an Integer for the
* prescaler
*/
typedef struct {
uint32_t adc;
uint8_t sample_time;
uint32_t prescaler;
} diy_adc_config_t;
/*! \brief Initialize the on-board ADC.
* \param adc_config Struct containing the configuration of the ADC register
* \param channels Channel to be configured
* \param len_channels Number of channels in channels
*/
void diy_adc_init(diy_adc_config_t* adc_config, uint8_t channels[], uint8_t len_channels);
/*! \brief Reads the current ADC value from the channels.
* \param adc ADC peripheral
* \param channels Channels that should be read
* \param sample_val Array where the adc values are stored
* \param len_channels Number of channels to be read, sample_val and channels should be of same size
*/
void diy_adc_read(uint32_t adc, uint8_t channels[], uint16_t sample_val[], uint8_t len_channels);
#endif // DIY_ADC_H_INCLUDED
#ifndef DIY_GPIO_H_INCLUDED
#define DIY_GPIO_H_INCLUDED
#include <stdint.h>
/*!
* \defgroup gpio DIY GPIO Library
*/
/**
* \file diy_gpio.h DIY GPIO Library
* \ingroup gpio
* \brief Configure and use gpio pins
*/
/*!\brief Structure for initializing the GPIO Pins. For port, mode, type, speed
* and pull_up_down use the definitons from libDIY/drivers/include/diy_gpio.h.
* For alt_func see the STM32F411 data sheet and use an Interger from 0 to 15.
* \param port: GPIOA ... GPIOH
* \param mode: GPIO_MODE_OUTPUT (Pin as Output)
* GPIO_MODE_INPUT (Pin as Input)
GPIO_MODE_AF (Use Alternate function as described by alt_func, see data sheet)
GPIO_MODE_ANALOG (Use for ADC)
* \param type: GPIO_TYPE_PP (Use PushPull configuration)
GPIO_TYPE_OD (Use open drain configuration) https://electronics.stackexchange.com/questions/28091/push-pull-open-drain-pull-up-pull-down
* \param speed: GPIO_OSPEED_2MHZ, ..., GPIO_OSPEED_50MHZ
* \param pull_up_down: GPIO_PUPD_NONE, GPIO_PUPD_PULLUP, GPIO_PUPD_PULLDOWN
* \param alt_func: GPIO_AF0 ... GPIO_AF15
*/
typedef struct {
uint32_t port;
uint8_t mode;
uint8_t type;
uint8_t speed;
uint8_t pull_up_down;
uint8_t alt_func;
} diy_gpio_config_t;
/*!\brief Initialize the pins on one port with the same configuration
* \param gpio_config Struct containing the port register configuration
* \param pins Bitmask of the pins, if you want to use more than one pin OR-link
* them (GPIO1 | GPIO2 ...).
*/
void diy_gpio_init(diy_gpio_config_t* gpio_config, uint16_t pins);
/*!\brief Sets pins to high logic level
* \param port Port with the pins
* \param pin Bitmask of the pins
*/
void diy_gpio_set_pins(uint32_t port, uint16_t pin);
/*!\brief Sets pins to low logic level
* \param port Port with the pins
* \param pin Bitmask of the pins
*/
void diy_gpio_clear_pins(uint32_t port, uint16_t pin);
/*!\brief Inverts the pins logic level
* \param port Port with the pins
* \param pin Bitmask of the pins
*/
void diy_gpio_toggle_pins(uint32_t port, uint16_t pin);
/*!\brief Reads the current output status of one pin
* \param port Port with the pins
* \param pin Bitmask of the pins
* \returns 1 if pin is set to high, 0 otherwise
*/
uint8_t diy_gpio_read_pin_out(uint32_t port, uint16_t pin);
/*!\brief Reads the current logic levef of one pin
* \param port Port with the pin
* \param pin Bitmask of the pin
* \returns 1 if pin is pulled high, 0 otherweise
*/
uint8_t diy_gpio_read_pin(uint32_t port, uint16_t pin);
#endif //DIY_GPIO_H_INCLUDED
#ifndef DIY_INT_H_INCLUDED
#define DIY_INT_H_INCLUDED
#include <stdint.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
/*
*
*/
void diy_init_button_int(uint32_t pin, enum exti_trigger_type trigger, uint8_t priority);
#endif // DIY_INT_H_INCLUDED
#ifndef DIY_TIM_H_INCLUDED
#define DIY_TIM_H_INCLUDED
#include <stdint.h>
#include "libopencm3/stm32/timer.h"
// Channel Polarity Definitions
#define TIM_CCER_CCxNP_LOW 0
#define TIM_CCER_CCxNP_HIGH 1
/*! \brief Structure for configuring a timer. Use the definitions in libDIY/drivers
* include/diy_tim.h for timer, clock_div, alignment and count_direction. Use an
* integer for period
*/
typedef struct {
uint32_t timer;
uint32_t clock_div;
uint32_t alignment;
uint32_t count_direction;
uint32_t period;
} diy_tim_config_t;
/*! \brief Structure for configuring a channel. Use definitions in libDIY/drivers
* include/diy_tim.h for channel, mode and polarity. Use an integer for prescaler,
* repetition_counter and compare_value.
*/
typedef struct {
uint8_t channel;
uint8_t mode;
uint32_t prescaler;
uint32_t repetition_counter;
uint8_t polarity;
uint32_t compare_value;
} diy_tim_channel_config_t;
/* Timers available:
* TIM2
* TIM3
* TIM4
* TIM5 ! If you use the ezs_counter, do not use TIM5 !
* TIM9
* TIM10
* TIM11
* ! TIM 1 is an advanced timer and can not be used with this interface !
*/
/*! \brief Initialize a timer peripheral and starts the timer's counter
* \param tim_config Struct containing the configuration of the timer's register
*/
void diy_tim_init(diy_tim_config_t* tim_config);
/* Channels and pins for
* TIM2: (PA0, PA5, PA15)/CH1, (PA1, PB3)/CH2, (PA2, PB10)/CH3, PA3/CH4
* TIM3: (PA6, PB4, PC6)/CH1, (PA7, PB5, PC7)/CH2, (PB0, PC8)/CH3, (PB1, PC9)/CH4,
* TIM4: (PB6, PD12)/CH1, (PB7, PD13)/CH2, (PB8, PD14)/CH3, (PB9, PD15)/CH4
* TIM5: PA0/CH1, PA1/CH1, PA2/CH3, PA3/CH4
* TIM9: PA2/CH1, PA3/CH2
* TIM10: PB8/CH1
* TIM11: PB9/CH1
*/
/*! \brief Initialize a timer output channel and enables it's output
* \param channel_config Struct containing the configuration of the channel's register
* \param timer Timer peripheral of the channel
*/
void diy_tim_channel_init(diy_tim_channel_config_t* channel_config, uint32_t timer);
/*! \brief Starts the timer's counter
* \param timer Timer peripheral
*/
void diy_tim_start(uint32_t timer);
/*! \brief Stops the timer's counter
* \param timer Timer peripheral
*/
void diy_tim_stop(uint32_t timer);
/*! \brief Starts the channel's output
* \param timer Timer peripheral
* \param channel Channel ID
*/
void diy_tim_channel_start(uint32_t timer, enum tim_oc_id channel);
/*! \brief Stops the channel's output
* \param timer Timer peripheral
* \param channel Channel ID
*/
void diy_tim_channel_stop(uint32_t timer, enum tim_oc_id channel);
/*! \brief Sets the channel's capture compare value
* \param timer Timer peripheral
* \param channel Channel ID
* \param compare_value New capture compare value
*/
void diy_tim_channel_set_compare_value(uint32_t timer, enum tim_oc_id channel, uint32_t compare_value);
#endif // DIY_TIM_H_INCLUDED
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/adc.h>
#include "diy_adc.h"
#include "diy_gpio.h"
/*
* Function for initializing the onboard ADC and the channels with linked
* pins. The function assumes that the GPIO Pins have already been configured
* for ADC use.
*/
void diy_adc_init(diy_adc_config_t* adc_config, uint8_t channels[], uint8_t len_channels){
// Activate Clock for ADC, STM32F411E only has one ADC, so no selection is necessary
rcc_periph_clock_enable(RCC_ADC1);
// Power off ADC during setup (necessary?)
adc_power_off(adc_config->adc);
// Turn of scanning mode
adc_disable_scan_mode(adc_config->adc);
// Set sample time for channels
uint8_t i;
// Alternative: adc_set_sample_time_on_all_channels(adc, time)
for(i = 0; i < len_channels; i++){
adc_set_sample_time(adc_config->adc, channels[i], adc_config->sample_time);
}
// Power on ADC after setup
adc_power_on(adc_config->adc);
// ADC should be ready after 3 ms
}
/*
* Function to read out a set of up to 16 channels and return their
* values in array of the same order as the input array's channels
*/
void diy_adc_read(uint32_t adc, uint8_t channels[], uint16_t sample_val[], uint8_t len_channels){
/* adc_read_regular returns uin32_t, but only lower 16 bits are used when
* only one ADC is present or more ADC2 is available and dual mode is on.
*/
// Set channels to be sampled in the step
adc_set_regular_sequence(adc, len_channels, channels);
// Start sampling channels and wait for finish
uint8_t i;
for(i = 0;i < len_channels;i++){
adc_start_conversion_regular(adc);
while(!adc_eoc(adc)); // Flag set after each channels conversion
sample_val[i] = (uint16_t) adc_read_regular(adc);
}
}
#include "diy_gpio.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
static enum rcc_periph_clken diy_gpio_get_rcc_periph(uint32_t port){
enum rcc_periph_clken rcc_periph;
switch(port){
case GPIOA: rcc_periph = RCC_GPIOA;
break;
case GPIOB: rcc_periph = RCC_GPIOB;
break;
case GPIOC: rcc_periph = RCC_GPIOC;
break;
case GPIOD: rcc_periph = RCC_GPIOD;
break;
case GPIOE: rcc_periph = RCC_GPIOE;
break;
case GPIOH: rcc_periph = RCC_GPIOH;
break;
default: rcc_periph = 0xFFFF;
break;
}
return rcc_periph;
}
void diy_gpio_init(diy_gpio_config_t* gpio_config, uint16_t pins){
// Get RCC define based on Port
enum rcc_periph_clken rcc_periph;
rcc_periph = diy_gpio_get_rcc_periph(gpio_config->port);
if(rcc_periph == 0xFFFF){
return;
}
else{
// Activate clock for Port
rcc_periph_clock_enable(rcc_periph);
}
// Set GPIO port registers MODER, PUPDR
gpio_mode_setup(gpio_config->port,
gpio_config->mode,
gpio_config->pull_up_down,
pins);
// Depending on pin mode set other registers
switch(gpio_config->mode){
// Set GPIO port registers OTYPER, OSPEEDR for output mode
case GPIO_MODE_OUTPUT: gpio_set_output_options(gpio_config->port,
gpio_config->type,
gpio_config->speed,
pins);
gpio_clear(gpio_config->port, pins);
break;
// Set GPIO port register AFRL for alternative function mode
case GPIO_MODE_AF: gpio_set_af(gpio_config->port,
gpio_config->alt_func,
pins);
break;
default: break;
}
}
/* Wrapper function for libopencm3 set pin function to have a unified
* interface. For multiple pins OR-link them (GPIO1 | GPIO2 ...).
*/
void diy_gpio_set_pins(uint32_t port, uint16_t pin){
gpio_set(port, pin);
}
/* Wrapper function for libopencm3 clear pin function to have a unified
* interface. For multiple pins OR-link them (GPIO1 | GPIO2 ...).
*/
void diy_gpio_clear_pins(uint32_t port, uint16_t pin){
gpio_clear(port, pin);
}
/* Wrapper function for libopencm3 toggle pin function to have a unified
* interface. For multiple pins OR-link them (GPIO1 | GPIO2 ...).
*/
void diy_gpio_toggle_pins(uint32_t port, uint16_t pin){
gpio_toggle(port, pin);
}
/* Function to query the state of one output pin
* 1 if pin is set, 0 otherwise
*/
uint8_t diy_gpio_read_pin_out(uint32_t port, uint16_t pin){
uint16_t odr_reg = 0;
odr_reg = (uint16_t) GPIO_ODR(port);
if(odr_reg & pin){
return (uint8_t) 1;
}
return (uint8_t) 0;
}
uint8_t diy_gpio_read_pin(uint32_t port, uint16_t pin){
uint16_t idr_reg = 0;
idr_reg = gpio_port_read(port);
if(idr_reg & pin){
return (uint8_t) 1;
}
return (uint8_t) 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment