Compare commits
36 Commits
02a673546e
...
40093322c3
Author | SHA1 | Date | |
---|---|---|---|
40093322c3 | |||
0da3ebed6f | |||
c6dd4e735c | |||
13c528163d | |||
26f8e7ae99 | |||
1745a7e2b2 | |||
94b59918fc | |||
d095e26c9e | |||
09507b5734 | |||
29fed8328c | |||
bb898adfac | |||
e4770698e2 | |||
f04a5c7930 | |||
d80ce20675 | |||
673e651910 | |||
14ba09a716 | |||
69c00ff3d3 | |||
48fea3d36e | |||
8bbc2e60f8 | |||
07793fb490 | |||
827f5c2066 | |||
1f5a535076 | |||
c32bb559f3 | |||
a6fa35b1ea | |||
825de053ce | |||
3ac252db69 | |||
4c7909adac | |||
1e678c3ce8 | |||
5f9bc29701 | |||
87db430a17 | |||
314bc278eb | |||
bccacc253c | |||
850d84140e | |||
8af10dd52c | |||
23e754ab2a | |||
1dcdb3b603 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
||||
*.hex
|
||||
*.map
|
||||
|
||||
*.autosave
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "stm-firmware/shellmatta"]
|
||||
path = stm-firmware/shellmatta
|
||||
url = https://git.shimatta.de/mhu/shellmatta
|
8665
measurement-data/1000OhmSamplingFixedStableCircuit.csv
Normal file
8665
measurement-data/1000OhmSamplingFixedStableCircuit.csv
Normal file
File diff suppressed because it is too large
Load Diff
6735
measurement-data/1000OhmSamplingFixedStableCircuitDay2.csv
Normal file
6735
measurement-data/1000OhmSamplingFixedStableCircuitDay2.csv
Normal file
File diff suppressed because it is too large
Load Diff
18252
measurement-data/1000OhmSamplingFixedStableCircuitDay3.csv
Normal file
18252
measurement-data/1000OhmSamplingFixedStableCircuitDay3.csv
Normal file
File diff suppressed because it is too large
Load Diff
13473
measurement-data/1000OhmSamplingFixedStableCircuitDay4.csv
Normal file
13473
measurement-data/1000OhmSamplingFixedStableCircuitDay4.csv
Normal file
File diff suppressed because it is too large
Load Diff
7476
measurement-data/1000OhmSamplingFixedStableCircuitHT.csv
Normal file
7476
measurement-data/1000OhmSamplingFixedStableCircuitHT.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -75,6 +75,36 @@
|
||||
" return temp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def plot_histogram(ax, data, bin_count, title, signal_name):\n",
|
||||
" n, bins, patches = ax.hist(data, bin_count, density=1, color='navy')\n",
|
||||
" mu = np.mean(data)\n",
|
||||
" sigma = np.std(data)\n",
|
||||
" y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma * (bins - mu))**2))\n",
|
||||
" ax.plot(bins, y, color='darkorange')\n",
|
||||
" ax.set_title(title)\n",
|
||||
" ax.set_ylabel(signal_name + ' probability (normalized)')\n",
|
||||
" ax.set_xlabel(signal_name)\n",
|
||||
" # Plot sigma and mu lines\n",
|
||||
" ax.axvline(x=mu-sigma, ls='--', color='magenta')\n",
|
||||
" ax.axvline(x=mu+sigma, ls='--', color='magenta')\n",
|
||||
" ax.axvline(x=mu, ls='--', color='lawngreen')\n",
|
||||
"\n",
|
||||
" #Plot textbox\n",
|
||||
" textstr = '\\n'.join((\n",
|
||||
" r'$\\mu=%.2f$' % (mu, ),\n",
|
||||
" r'$\\sigma=%.4f$' % (sigma, ),\n",
|
||||
" r'$N_{Sa} =%d$' % (len(data), )))\n",
|
||||
" props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)\n",
|
||||
" ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14,\n",
|
||||
" verticalalignment='top', bbox=props)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@ -117,33 +147,14 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(28,20))\n",
|
||||
"plot_data = [(one_k_sampling_trafo, '1 kOhm Sampling Transformer powered', 0), (two_k_sampling_trafo, '2 kOhm Sampling Transformer powered' , 0), (constant_sampling, '1 kOhm Sampling', 100)]\n",
|
||||
"signal_list = [('adc_results.pa2_raw', 20), ('ext_lf_corr', 20), ('temp_calculated', 20)]\n",
|
||||
"signal_list = [('ext_lf_corr', 20), ('temp_calculated', 20)]\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(nrows=len(plot_data), ncols=len(signal_list), figsize=(28,20))\n",
|
||||
"\n",
|
||||
"for (data_df, title, start_idx), ax_rows in zip(plot_data, axes):\n",
|
||||
" for ax,sig in zip(ax_rows, signal_list):\n",
|
||||
" n, bins, patches = ax.hist(data_df[sig[0]][start_idx:], sig[1], density=1, color='navy')\n",
|
||||
" mu = np.mean(data_df[sig[0]][start_idx:])\n",
|
||||
" sigma = np.std(data_df[sig[0]][start_idx:])\n",
|
||||
" y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma * (bins - mu))**2))\n",
|
||||
" ax.plot(bins, y, color='darkorange')\n",
|
||||
" ax.set_title(title)\n",
|
||||
" ax.set_ylabel(sig[0] + ' probability (normalized)')\n",
|
||||
" ax.set_xlabel(sig[0])\n",
|
||||
" # Plot sigma and mu lines\n",
|
||||
" ax.axvline(x=mu-sigma, ls='--', color='magenta')\n",
|
||||
" ax.axvline(x=mu+sigma, ls='--', color='magenta')\n",
|
||||
" ax.axvline(x=mu, ls='--', color='lawngreen')\n",
|
||||
" \n",
|
||||
" #Plot textbox\n",
|
||||
" textstr = '\\n'.join((\n",
|
||||
" r'$\\mu=%.2f$' % (mu, ),\n",
|
||||
" r'$\\sigma=%.2f$' % (sigma, ),\n",
|
||||
" r'$N_{Sa} =%d$' % (len(data_df[sig[0]][start_idx:], ))))\n",
|
||||
" props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)\n",
|
||||
" ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14,\n",
|
||||
" verticalalignment='top', bbox=props)\n",
|
||||
" plot_histogram(ax, data_df[sig[0]][start_idx:], sig[1], title,sig[0])\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"plt.tight_layout()\n",
|
||||
@ -310,6 +321,77 @@
|
||||
"ax.set_title('Cooldown without airflow | Convection has to be taken into account') \n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"# Target Implementation Sampling of 1k Resistor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Histograms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Read in data\n",
|
||||
"kilo_ohm_sampling1 = pd.read_csv(r'1000OhmSamplingFixedStableCircuit.csv')\n",
|
||||
"kilo_ohm_sampling1_ht = pd.read_csv(r'1000OhmSamplingFixedStableCircuitHT.csv')\n",
|
||||
"kilo_ohm_sampling2 = pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay2.csv')\n",
|
||||
"plot_data_tuples = [(kilo_ohm_sampling1, 'Day 1 Sampling -- Stable circuit -- RT'),\n",
|
||||
" (kilo_ohm_sampling1_ht, 'Day 1 Sampling -- Stable circuit -- HT'),\n",
|
||||
" (kilo_ohm_sampling2, 'Day 2 Sampling -- Stable circuit'),\n",
|
||||
" (pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay3.csv'), 'Day 3 Sampling -- Stable Circuit (improved)'),\n",
|
||||
" (pd.read_csv(r'1000OhmSamplingFixedStableCircuitDay4.csv'), 'Day 4 Sampling -- Stable Circuit (improved)')\n",
|
||||
" ]\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"# def plot_histogram(ax, data, bin_count, title, signal_name):\n",
|
||||
"# def calculate_temp_for_df(data_frame, resistance_col_name='ext_lf_corr', temp_col_name='temp_calculated'):\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(nrows=len(plot_data_tuples), ncols=2, sharex='col', figsize=(28, 8*len(plot_data_tuples)))\n",
|
||||
"\n",
|
||||
"if len(plot_data_tuples) == 1:\n",
|
||||
" axes = [axes]\n",
|
||||
"\n",
|
||||
"for df, title in plot_data_tuples:\n",
|
||||
" calculate_temp_for_df(df, resistance_col_name='pt1000_value')\n",
|
||||
"\n",
|
||||
"for (df,title),ax in zip(plot_data_tuples, axes):\n",
|
||||
" plot_histogram(ax[0], df['pt1000_value'], 21, title, 'PT1000 Resistance')\n",
|
||||
" plot_histogram(ax[1], df['temp_calculated'], 21, title, 'Calculated Temperature in °C')\n",
|
||||
" ax[0].grid()\n",
|
||||
" ax[1].grid()\n",
|
||||
"\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(calc_temp(1000.6)-calc_temp(1000.4))\n",
|
||||
"print(1/4096*2500)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
@ -3,18 +3,21 @@
|
||||
#Compiler: arm-none-eabi
|
||||
#####################################################################################
|
||||
#Add Files and Folders below#########################################################
|
||||
CFILES = main.c syscalls.c uart/uart.c cmsis_boot/system_stm32f4xx.c systick.c
|
||||
CFILES = main.c syscalls.c setup/system_stm32f4xx.c systick.c
|
||||
ASFILES = boot/startup_stm32f4xx.S
|
||||
INCLUDEPATH = -Icmsis -Iinclude
|
||||
|
||||
OBJDIR = obj
|
||||
target = reflow-controller
|
||||
LIBRARYPATH = -L. -Lmathlib
|
||||
LIBRARIES = # -larm_cortexM4lf_math
|
||||
LIBRARIES = -larm_cortexM4lf_math
|
||||
|
||||
DEFINES = -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DHSE_VALUE=8000000UL
|
||||
mapfile = memory-mapping
|
||||
|
||||
GIT_VER := $(shell git describe --always --dirty --tags)
|
||||
DEFINES += -DGIT_VER=$(GIT_VER)
|
||||
|
||||
ifneq ($(VERBOSE),true)
|
||||
QUIET=@
|
||||
else
|
||||
@ -23,6 +26,22 @@ endif
|
||||
|
||||
##Custom Files###
|
||||
CFILES += adc-meas.c
|
||||
|
||||
# Shellmatta
|
||||
CFILES += shellmatta/src/shellmatta.c shellmatta/src/shellmatta_autocomplete.c shellmatta/src/shellmatta_escape.c shellmatta/src/shellmatta_history.c shellmatta/src/shellmatta_utils.c shell.c
|
||||
INCLUDEPATH += -Ishellmatta/api
|
||||
# DEFINES += -DSHELLMATTA_STRIP_PRINTF
|
||||
|
||||
# RCC Manager
|
||||
CFILES += stm-periph/clock-enable-manager.c
|
||||
|
||||
CFILES += stm-periph/uart.c stm-periph/dma-ring-buffer.c
|
||||
|
||||
CFILES += digio.c
|
||||
|
||||
CFILES += stm-periph/unique-id.c
|
||||
|
||||
DEFINES += -DDEBUGBUILD
|
||||
#TODO
|
||||
|
||||
###################################################################################
|
||||
@ -37,7 +56,7 @@ LFLAGS += -Tstm32f407vet6_flash.ld -Wl,-Map=$(mapfile).map
|
||||
|
||||
CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -O0 -g
|
||||
|
||||
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter
|
||||
####################################################################################
|
||||
|
||||
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
|
||||
@ -81,7 +100,7 @@ mrproper: clean
|
||||
rm -f $(target).pro
|
||||
|
||||
clean:
|
||||
rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map
|
||||
rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
||||
qtproject:
|
||||
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
|
||||
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
|
||||
|
@ -1,30 +1,155 @@
|
||||
#include <adc-meas.h>
|
||||
#include <stm32f4xx.h>
|
||||
#include <stm32-gpio-macros.h>
|
||||
#include <reflow-controller/adc-meas.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <cmsis/core_cm4.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stdlib.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
|
||||
static float pt1000_offset;
|
||||
static float pt1000_sens_dev;
|
||||
static bool calibration_active;
|
||||
static float filter_alpha;
|
||||
static float pt1000_adc_raw_lf;
|
||||
static bool streaming_active;
|
||||
static volatile float pt1000_res_raw_lf;
|
||||
static volatile bool filter_ready;
|
||||
static volatile enum adc_p1000_error pt1000_error;
|
||||
|
||||
static volatile enum adc_pt1000_error pt1000_error;
|
||||
static volatile uint8_t * volatile streaming_flag_ptr = NULL;
|
||||
static uint32_t filter_startup_cnt;
|
||||
static volatile float adc_pt1000_raw_reading_hf;
|
||||
static volatile bool pt1000_measurement_active = false;
|
||||
static volatile uint16_t dma_sample_buffer[ADC_PT1000_DMA_AVG_SAMPLES];
|
||||
|
||||
#define ADC_TO_RES(adc) ((float)(adc) / 4096.0f * 2500.0f)
|
||||
|
||||
static inline void adc_pt1000_stop_sample_frequency_timer()
|
||||
{
|
||||
TIM2->CR1 &= ~TIM_CR1_CEN;
|
||||
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM2EN));
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_setup_sample_frequency_timer()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM2EN));
|
||||
|
||||
/* Divide 42 MHz peripheral clock by 42 */
|
||||
TIM2->PSC = (42UL-1UL);
|
||||
|
||||
/* Reload value */
|
||||
TIM2->ARR = ADC_PT1000_SAMPLE_CNT_DELAY;
|
||||
|
||||
/* Trigger output at update event */
|
||||
TIM2->CR2 = TIM_CR2_MMS_1;
|
||||
|
||||
/* Start Timer in downcounting mode with autoreload */
|
||||
TIM2->CR1 = TIM_CR1_DIR | TIM_CR1_CEN;
|
||||
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_disable_adc()
|
||||
{
|
||||
ADC1->CR2 &= ~ADC_CR2_ADON;
|
||||
DMA2_Stream0->CR = 0;
|
||||
|
||||
pt1000_measurement_active = false;
|
||||
|
||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable DMA Stream for ADC
|
||||
*
|
||||
* DMA2 Stream 0 is used. It will capture @ref ADC_PT1000_DMA_AVG_SAMPLES measurement values,
|
||||
* delete the two most extreme values
|
||||
* and calculate the avereage over the remaining values. This ensures, that one time errors are
|
||||
* not included in the measurement.
|
||||
*
|
||||
* After that, the moving average filter is fed with the values.
|
||||
*
|
||||
*/
|
||||
static inline void adc_pt1000_enable_dma_stream()
|
||||
{
|
||||
/* Enable peripheral clock for DMA2 */
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
||||
|
||||
/* Destination is the DMA sample buffer */
|
||||
DMA2_Stream0->M0AR = (uint32_t)dma_sample_buffer;
|
||||
|
||||
/* Source is the ADC data register */
|
||||
DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
|
||||
|
||||
/* Transfer size is ADC_PT1000_DMA_AVG_SAMPLES */
|
||||
DMA2_Stream0->NDTR = ADC_PT1000_DMA_AVG_SAMPLES;
|
||||
|
||||
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
|
||||
|
||||
/* Enable the stream in Peripheral-to-Memory mode with 16 bit data and a circular destination buffer
|
||||
* Enable interrupt generation on transfer complete
|
||||
*
|
||||
* Todo: Maybe use twice as big of a buffer and also use half-fill interrupt in order to prevent overruns
|
||||
*/
|
||||
DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
|
||||
DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
static inline void adc_pt1000_disable_dma_stream()
|
||||
{
|
||||
/* Disable the stream */
|
||||
DMA2_Stream0->CR = 0;
|
||||
|
||||
/* Disable clock if necessary */
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
||||
|
||||
/* Disable interrupt */
|
||||
NVIC_DisableIRQ(DMA2_Stream0_IRQn);
|
||||
}
|
||||
|
||||
void adc_pt1000_setup_meas()
|
||||
{
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
|
||||
RCC->AHB1ENR |= ADC_PT1000_PORT_RCC_MASK;
|
||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||
|
||||
ADC_PT1000_PORT->MODER |= ANALOG(ADC_PT1000_PIN);
|
||||
|
||||
/* Set S&H time for PT1000 ADC channel */
|
||||
#if ADC_PT1000_CHANNEL < 10
|
||||
ADC1->SMPR2 |= (7U << (3*ADC_PT1000_CHANNEL));
|
||||
#else
|
||||
ADC1->SMPR1 |= (7U << (3*(ADC_PT1000_CHANNEL-10)));
|
||||
#endif
|
||||
|
||||
ADC->CCR |= (0x2<<16);
|
||||
|
||||
/* Set watchdog limits */
|
||||
ADC1->HTR = ADC_PT1000_UPPER_WATCHDOG;
|
||||
ADC1->LTR = ADC_PT1000_LOWER_WATCHDOG;
|
||||
|
||||
/* Set length of sequence to 1 */
|
||||
ADC1->SQR1 = (0UL<<20);
|
||||
|
||||
/* Set channel as 1st element in sequence */
|
||||
ADC1->SQR3 = (ADC_PT1000_CHANNEL<<0);
|
||||
|
||||
ADC1->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
||||
ADC1->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||
|
||||
adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
|
||||
adc_pt1000_set_resistance_calibration(0, 0, false);
|
||||
pt1000_res_raw_lf = 0.0f;
|
||||
|
||||
NVIC_EnableIRQ(ADC_IRQn);
|
||||
|
||||
adc_pt1000_enable_dma_stream();
|
||||
|
||||
adc_pt1000_setup_sample_frequency_timer();
|
||||
|
||||
pt1000_measurement_active = true;
|
||||
}
|
||||
|
||||
void adc_pt1000_set_moving_average_filter_param(float alpha)
|
||||
{
|
||||
filter_alpha = alpha;
|
||||
filter_ready = false;
|
||||
filter_startup_cnt = ADC_FILTER_STARTUP_CYCLES;
|
||||
}
|
||||
|
||||
void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_deviation, bool active)
|
||||
@ -44,6 +169,15 @@ void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_dev
|
||||
*active = calibration_active;
|
||||
}
|
||||
|
||||
static inline float adc_pt1000_apply_calibration(float raw_resistance)
|
||||
{
|
||||
if (calibration_active)
|
||||
return pt1000_res_raw_lf * (1.0f + pt1000_sens_dev) + pt1000_offset;
|
||||
else
|
||||
return raw_resistance;
|
||||
|
||||
}
|
||||
|
||||
int adc_pt1000_get_current_resistance(float *resistance)
|
||||
{
|
||||
int ret_val = 0;
|
||||
@ -51,40 +185,35 @@ int adc_pt1000_get_current_resistance(float *resistance)
|
||||
if (!resistance)
|
||||
return -1001;
|
||||
|
||||
if (calibration_active)
|
||||
*resistance = ADC_TO_RES(pt1000_adc_raw_lf) * (1 + pt1000_sens_dev) + pt1000_offset;
|
||||
else
|
||||
*resistance = ADC_TO_RES(pt1000_adc_raw_lf);
|
||||
*resistance = adc_pt1000_apply_calibration(pt1000_res_raw_lf);
|
||||
|
||||
if (adc_pt1000_check_error()) {
|
||||
ret_val = -100;
|
||||
goto return_value;
|
||||
}
|
||||
|
||||
if (streaming_active) {
|
||||
ret_val = 1;
|
||||
goto return_value;
|
||||
}
|
||||
if (!filter_ready)
|
||||
{
|
||||
if (!filter_ready) {
|
||||
ret_val = 2;
|
||||
goto return_value;
|
||||
}
|
||||
|
||||
return_value:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int adc_pt1000_stream_raw_value_to_memory(uint16_t *adc_array, uint32_t length, volatile uint8_t *flag_to_set)
|
||||
/*
|
||||
int adc_pt1000_stream_raw_value_to_memory(float *adc_array, uint32_t length, volatile uint8_t *flag_to_set)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, float *raw_source, uint32_t count)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, uint16_t *raw_source, uint32_t count)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
enum adc_p1000_error adc_pt1000_check_error()
|
||||
enum adc_pt1000_error adc_pt1000_check_error()
|
||||
{
|
||||
return pt1000_error;
|
||||
}
|
||||
@ -94,9 +223,53 @@ void adc_pt1000_clear_error()
|
||||
pt1000_error = ADC_PT1000_NO_ERR;
|
||||
}
|
||||
|
||||
static void adc_pt1000_filter(uint16_t adc_value)
|
||||
void adc_pt1000_disable()
|
||||
{
|
||||
pt1000_adc_raw_lf = (1-filter_alpha) * pt1000_adc_raw_lf + filter_alpha * (float)adc_value;
|
||||
adc_pt1000_disable_adc();
|
||||
adc_pt1000_stop_sample_frequency_timer();
|
||||
adc_pt1000_disable_dma_stream();
|
||||
|
||||
filter_ready = false;
|
||||
pt1000_res_raw_lf = 0.0f;
|
||||
|
||||
if (streaming_flag_ptr) {
|
||||
*streaming_flag_ptr = -3;
|
||||
streaming_flag_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_prefiltered_value)
|
||||
{
|
||||
if (!filter_ready && --filter_startup_cnt <= 0)
|
||||
filter_ready = true;
|
||||
|
||||
pt1000_res_raw_lf = (1.0f-filter_alpha) * pt1000_res_raw_lf + filter_alpha * ADC_TO_RES(adc_prefiltered_value);
|
||||
}
|
||||
|
||||
static inline __attribute__((optimize("O3"))) float adc_pt1000_dma_avg_pre_filter()
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t sum = 0;
|
||||
uint16_t max_val = 0U;
|
||||
uint16_t min_val = 65535U;
|
||||
uint16_t sample;
|
||||
|
||||
for (i = 0; i < ADC_PT1000_DMA_AVG_SAMPLES; i++) {
|
||||
sample = dma_sample_buffer[i];
|
||||
|
||||
/* Update min and max trackers */
|
||||
max_val = (sample > max_val ? sample : max_val);
|
||||
min_val = (sample < min_val ? sample : min_val);
|
||||
|
||||
/* Sum up all values (for average) */
|
||||
sum += sample;
|
||||
}
|
||||
|
||||
/* Delete max and min vals from sum */
|
||||
sum = sum - (uint32_t)max_val - (uint32_t)min_val;
|
||||
|
||||
/* Divide to get average and return */
|
||||
return (float)sum / (float)(ADC_PT1000_DMA_AVG_SAMPLES-2);
|
||||
}
|
||||
|
||||
void ADC_IRQHandler(void)
|
||||
@ -104,20 +277,44 @@ void ADC_IRQHandler(void)
|
||||
uint32_t adc1_sr;
|
||||
|
||||
adc1_sr = ADC1->SR;
|
||||
if (ADC1->SR & ADC_SR_EOC) {
|
||||
ADC1->SR &= ~ADC_SR_EOC;
|
||||
adc_pt1000_filter(ADC1->DR);
|
||||
}
|
||||
|
||||
if (adc1_sr & ADC_SR_OVR) {
|
||||
ADC1->SR &= ~ADC_SR_OVR;
|
||||
pt1000_error = ADC_PT1000_OVERFLOW;
|
||||
pt1000_error |= ADC_PT1000_OVERFLOW;
|
||||
/* Disable ADC in case of overrrun*/
|
||||
ADC1->CR2 &= ADC_CR2_ADON;
|
||||
adc_pt1000_disable();
|
||||
if (streaming_flag_ptr) {
|
||||
*streaming_flag_ptr = -1;
|
||||
streaming_flag_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (adc1_sr & ADC_SR_AWD) {
|
||||
ADC1->SR &= ~ADC_SR_AWD;
|
||||
pt1000_error = ADC_PT1000_WATCHDOG_ERROR;
|
||||
pt1000_error |= ADC_PT1000_WATCHDOG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler()
|
||||
{
|
||||
uint32_t lisr;
|
||||
float adc_val;
|
||||
|
||||
lisr = DMA2->LISR;
|
||||
DMA2->LIFCR = lisr;
|
||||
|
||||
if (lisr & DMA_LISR_TCIF0) {
|
||||
/* Samples Transfered */
|
||||
adc_val = adc_pt1000_dma_avg_pre_filter();
|
||||
adc_pt1000_raw_reading_hf = adc_val;
|
||||
|
||||
/* Call moving average filter */
|
||||
adc_pt1000_filter(adc_val);
|
||||
}
|
||||
|
||||
if (lisr & DMA_LISR_TEIF0) {
|
||||
/* Wait for watchdog to kick in */
|
||||
while(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
120
stm-firmware/digio.c
Normal file
120
stm-firmware/digio.c
Normal file
@ -0,0 +1,120 @@
|
||||
#include <reflow-controller/digio.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
|
||||
static const uint8_t digio_pins[] = {DIGIO_PINS};
|
||||
static const uint8_t digio_default_io[] = {DIGIO_INOUT_DEFAULT};
|
||||
static const uint8_t digio_default_altfunc[] = {DIGIO_ALTFUNC_DEFAULT};
|
||||
|
||||
static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func)
|
||||
{
|
||||
DIGIO_PORT->MODER &= MODER_DELETE(bit_no);
|
||||
switch (in_out) {
|
||||
case 2:
|
||||
DIGIO_PORT->MODER |= ALTFUNC(bit_no);
|
||||
SETAF(DIGIO_PORT, bit_no, alt_func);
|
||||
break;
|
||||
case 1:
|
||||
DIGIO_PORT->MODER |= OUTPUT(bit_no);
|
||||
break;
|
||||
case 0: /* expected fallthrough */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void digio_setup_default_all()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(DIGIO_RCC_MASK));
|
||||
|
||||
for (i = 0; i < COUNT_OF(digio_pins); i++) {
|
||||
digio_setup_pin_int(digio_pins[i], digio_default_io[i], digio_default_altfunc[i]);
|
||||
if (digio_default_io[i] == 1)
|
||||
digio_set(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func)
|
||||
{
|
||||
if (num >= COUNT_OF(digio_pins))
|
||||
return;
|
||||
digio_setup_pin_int(digio_pins[num], in_out, alt_func);
|
||||
}
|
||||
|
||||
void digio_set(uint8_t num, int val)
|
||||
{
|
||||
if (num >= COUNT_OF(digio_pins))
|
||||
return;
|
||||
if (val)
|
||||
DIGIO_PORT->ODR |= (1<<digio_pins[num]);
|
||||
else
|
||||
DIGIO_PORT->ODR &= ~(1<<digio_pins[num]);
|
||||
}
|
||||
|
||||
int digio_get(uint8_t num)
|
||||
{
|
||||
if (num >= COUNT_OF(digio_pins))
|
||||
return -1;
|
||||
|
||||
if ((DIGIO_PORT->MODER & (0x3<<digio_pins[num])) == OUTPUT(digio_pins[num]))
|
||||
return (DIGIO_PORT->ODR & (1<<digio_pins[num]) ? 1 : 0);
|
||||
else
|
||||
return (DIGIO_PORT->IDR & (1<<digio_pins[num]) ? 1 : 0);
|
||||
}
|
||||
|
||||
static const uint8_t led_pins[] = {LED_PINS};
|
||||
|
||||
void led_setup()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LED_RCC_MASK));
|
||||
for (i = 0; i < COUNT_OF(led_pins); i++) {
|
||||
LED_PORT->MODER &= MODER_DELETE(led_pins[i]);
|
||||
LED_PORT->MODER |= OUTPUT(led_pins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void led_set(uint8_t num, int val)
|
||||
{
|
||||
if (num >= COUNT_OF(led_pins))
|
||||
return;
|
||||
if (val)
|
||||
LED_PORT->ODR |= (1<<led_pins[num]);
|
||||
else
|
||||
LED_PORT->ODR &= ~(1<<led_pins[num]);
|
||||
}
|
||||
|
||||
int led_get(uint8_t num)
|
||||
{
|
||||
if (num >= COUNT_OF(led_pins))
|
||||
return -1;
|
||||
|
||||
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
|
||||
}
|
||||
|
||||
void loudspeaker_setup()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LOUDSPEAKER_RCC_MASK));
|
||||
|
||||
LOUDSPEAKER_PORT->MODER &= MODER_DELETE(LOUDSPEAKER_PIN);
|
||||
LOUDSPEAKER_PORT->MODER |= OUTPUT(LOUDSPEAKER_PIN);
|
||||
|
||||
loudspeaker_set(0);
|
||||
}
|
||||
void loudspeaker_set(int val)
|
||||
{
|
||||
if (val)
|
||||
LOUDSPEAKER_PORT->ODR |= (1<<LOUDSPEAKER_PIN);
|
||||
else
|
||||
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||
}
|
||||
int loudspeaker_get()
|
||||
{
|
||||
return ((LOUDSPEAKER_PORT->ODR & (1<<LOUDSPEAKER_PIN)) ? 1 : 0);
|
||||
}
|
@ -151,9 +151,9 @@
|
||||
#endif
|
||||
|
||||
#include <stdint.h> /* standard types definitions */
|
||||
#include <core_cmInstr.h> /* Core Instruction Access */
|
||||
#include <core_cmFunc.h> /* Core Function Access */
|
||||
#include <core_cm4_simd.h> /* Compiler specific SIMD Intrinsics */
|
||||
#include <cmsis/core_cmInstr.h> /* Core Instruction Access */
|
||||
#include <cmsis/core_cmFunc.h> /* Core Function Access */
|
||||
#include <cmsis/core_cm4_simd.h> /* Compiler specific SIMD Intrinsics */
|
||||
|
||||
#endif /* __CORE_CM4_H_GENERIC */
|
||||
|
14
stm-firmware/include/helper-macros/helper-macros.h
Normal file
14
stm-firmware/include/helper-macros/helper-macros.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __HELPER_MACROS_H__
|
||||
#define __HELPER_MACROS_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define xstr(x) str(x)
|
||||
#define str(x) #x
|
||||
|
||||
#define CONCATX(x,y) CONCAT(x,y)
|
||||
#define CONCAT(x,y) x##y
|
||||
|
||||
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
|
||||
|
||||
#endif /* __HELPER_MACROS_H__ */
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stm32f4xx.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
/**
|
||||
* @brief Moving average filter coefficient for PT1000 measurement
|
||||
*/
|
||||
@ -12,30 +12,34 @@
|
||||
/**
|
||||
* @brief ADC channel number of PT1000 sensor input
|
||||
*/
|
||||
#define ADC_PT1000_CHANNEL 2
|
||||
#define ADC_PT1000_CHANNEL 2U
|
||||
|
||||
#define ADC_PT1000_PORT GPIOA
|
||||
#define ADC_PT1000_PORT_RCC_MASK RCC_AHB1ENR_GPIOAEN
|
||||
|
||||
#define ADC_PT1000_PIN 2
|
||||
#define ADC_PT1000_PIN 2U
|
||||
|
||||
#define ADC_FILTER_STARTUP_CYCLES 200
|
||||
#define ADC_FILTER_STARTUP_CYCLES 800U
|
||||
|
||||
#define ADC_PT1000_SAMPLE_CNT_DELAY 1000U
|
||||
|
||||
#define ADC_PT1000_DMA_AVG_SAMPLES 6U
|
||||
|
||||
/**
|
||||
* @brief Lower value for valid input range for PT1000 measurement
|
||||
*
|
||||
* If the input of the PT1000 sensor is below this value, an error is thrown. This is used to disable the temperature control loop
|
||||
*/
|
||||
#define ADC_PT1000_LOWER_WATCHDOG 100
|
||||
#define ADC_PT1000_LOWER_WATCHDOG 200U
|
||||
|
||||
/**
|
||||
* @brief Upper value for valid input range for PT1000 measurement
|
||||
*
|
||||
* If the input of the PT1000 sensor is above this value, an error is thrown. This is used to disable the temperature control loop
|
||||
*/
|
||||
#define ADC_PT1000_UPPER_WATCHDOG 4000
|
||||
#define ADC_PT1000_UPPER_WATCHDOG 4000U
|
||||
|
||||
enum adc_p1000_error {ADC_PT1000_NO_ERR= 0, ADC_PT1000_WATCHDOG_ERROR=-1, ADC_PT1000_OVERFLOW=2};
|
||||
enum adc_pt1000_error {ADC_PT1000_NO_ERR= 0, ADC_PT1000_WATCHDOG_ERROR=(1UL<<0), ADC_PT1000_OVERFLOW=(1UL<<1)};
|
||||
|
||||
/**
|
||||
* @brief This function sets up the ADC measurement fo the external PT1000 temperature sensor
|
||||
@ -86,8 +90,7 @@ void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_dev
|
||||
* If the reistance calibration is enabled, this function applies the calculations of the raw reistance reading and
|
||||
* returns the corrected value.
|
||||
*
|
||||
* If an ADC error is set, the status is negative. If the ADC is in streaming mode, the reistance reading is disabled and
|
||||
* the status is 1. The status is 2 during the first measurements with a given filter setting. Technically, the resistance value is
|
||||
* If an ADC error is set, the status is negative. The status is 2 during the first measurements with a given filter setting. Technically, the resistance value is
|
||||
* correct but the filter is not stable yet.
|
||||
* Use adc_pt1000_check_error to check the error and reinitialize the ADC.
|
||||
*
|
||||
@ -102,24 +105,25 @@ int adc_pt1000_get_current_resistance(float *resistance);
|
||||
*
|
||||
* Streaming is done using DMA2 Stream0.
|
||||
* This function is used for gathering fullspeed sampling data for external interfaces or calibration
|
||||
* During streaming, the adc_pt1000_get_current_resistance() function will return an error
|
||||
*
|
||||
* @param adc_array Array to stream data to
|
||||
* @param length Amount of data points to be measured
|
||||
* @param flag_to_set This flag is set to 1 once the data has been measured and is transferred. A negative value indicates an error
|
||||
* @return 0 if measurement could be started
|
||||
*/
|
||||
int adc_pt1000_stream_raw_value_to_memory(uint16_t *adc_array, uint32_t length, volatile uint8_t *flag_to_set);
|
||||
int adc_pt1000_stream_raw_value_to_memory(float *adc_array, uint32_t length, volatile uint8_t *flag_to_set);
|
||||
|
||||
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, uint16_t *raw_source, uint32_t count);
|
||||
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, float *raw_source, uint32_t count);
|
||||
|
||||
/**
|
||||
* @brief Check if the ADC measurement experienced any kind of error (DMA, Analog Watchdog, etc...)
|
||||
*
|
||||
* In case of an error, it may be necessary to call adc_pt1000_setup_meas() again in order to recover from the error
|
||||
*/
|
||||
enum adc_p1000_error adc_pt1000_check_error();
|
||||
enum adc_pt1000_error adc_pt1000_check_error();
|
||||
|
||||
void adc_pt1000_clear_error();
|
||||
|
||||
void adc_pt1000_disable();
|
||||
|
||||
#endif // __ADCMEAS_H__
|
47
stm-firmware/include/reflow-controller/digio.h
Normal file
47
stm-firmware/include/reflow-controller/digio.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef __DIGIO_H__
|
||||
#define __DIGIO_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
|
||||
#define DIGIO_PORT GPIOB
|
||||
#define DIGIO_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
||||
#define DIGIO_PINS 4,5,6,7
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
#define DIGIO_INOUT_DEFAULT 0,0,0,0
|
||||
#define DIGIO_ALTFUNC_DEFAULT 0,0,0,0
|
||||
#else
|
||||
#define DIGIO_INOUT_DEFAULT 0,0,2,2
|
||||
#define DIGIO_ALTFUNC_DEFAULT 0,0,7,7
|
||||
#endif
|
||||
|
||||
#define BEEPER_PORT GPIOB
|
||||
#define BEEPER_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
||||
|
||||
|
||||
void digio_setup_default_all();
|
||||
|
||||
void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func);
|
||||
void digio_set(uint8_t num, int val);
|
||||
int digio_get(uint8_t num);
|
||||
|
||||
#define LED_PORT GPIOB
|
||||
#define LED_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
||||
#define LED_PINS 2,3
|
||||
|
||||
void led_setup();
|
||||
void led_set(uint8_t num, int val);
|
||||
int led_get(uint8_t num);
|
||||
|
||||
#define LOUDSPEAKER_PORT GPIOB
|
||||
#define LOUDSPEAKER_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
||||
#define LOUDSPEAKER_PIN 1
|
||||
|
||||
void loudspeaker_setup();
|
||||
void loudspeaker_set(int val);
|
||||
int loudspeaker_get();
|
||||
|
||||
|
||||
#endif /* __DIGIO_H__ */
|
13
stm-firmware/include/reflow-controller/shell.h
Normal file
13
stm-firmware/include/reflow-controller/shell.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <shellmatta.h>
|
||||
|
||||
shellmatta_handle_t shell_init(void);
|
||||
|
||||
void shell_handle_input(shellmatta_handle_t shell, const char *data, size_t len);
|
||||
|
||||
void shell_print_string(shellmatta_handle_t shell, const char *string);
|
||||
|
||||
#endif /* __SHELL_H__ */
|
48
stm-firmware/include/stm-periph/clock-enable-manager.h
Normal file
48
stm-firmware/include/stm-periph/clock-enable-manager.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef __CLOCK_ENABLE_MANAGER_H__
|
||||
#define __CLOCK_ENABLE_MANAGER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
|
||||
/**
|
||||
* @brief The RCC Enable Manager uses static memory with a fixed maximum
|
||||
*/
|
||||
#define RCC_ENABLE_MANAGER_STATIC 1U
|
||||
|
||||
#if RCC_ENABLE_MANAGER_STATIC
|
||||
#define RCC_ENABLE_MANAGER_COUNT 30U
|
||||
#else
|
||||
#error "RCC Enable Manager not yet implemented with dynamic memory"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable Clock for peripheral by setting the corresponding bit (@p bit_no) to one
|
||||
*
|
||||
* This function also keeps a enable count on each bit that is set, in order to allow nested enables/disables
|
||||
*
|
||||
* If there is no more space to track a new register bit in memory (either due to the static limit or due to no remaining heap space),
|
||||
* the function still enables the peripheral clock but does not track it and returns -1
|
||||
*
|
||||
* @param rcc_enable_register
|
||||
* @param bit_no
|
||||
*
|
||||
* @return 0 if successful
|
||||
*/
|
||||
int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no);
|
||||
|
||||
/**
|
||||
* @brief Disable clock for peripheral and decrement the enaböe-counter of that bit.
|
||||
*
|
||||
* If there is no bit entry in the counting table yet, teh peripheral clock is not disabled and error code
|
||||
* -1 is returned.
|
||||
*
|
||||
* If the count reaches zero, the element is removed from the list to make room for new ones
|
||||
*
|
||||
* @param rcc_enable_register Register to disable the bit in
|
||||
* @param bit_no Bit number (0 to 31) of the bit to disable
|
||||
* @return 0 if successful
|
||||
*/
|
||||
int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no);
|
||||
|
||||
|
||||
#endif /* __CLOCK_ENABLE_MANAGER_H__ */
|
110
stm-firmware/include/stm-periph/dma-ring-buffer.h
Normal file
110
stm-firmware/include/stm-periph/dma-ring-buffer.h
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef __DMA_RING_BUFFER_H__
|
||||
#define __DMA_RING_BUFFER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief DMA ring buffer for data transfer from peripheral to memory
|
||||
*/
|
||||
struct dma_ring_buffer_to_mem {
|
||||
void *data_ptr; /**< @brief Ring buffer */
|
||||
size_t buffer_count; /**< @brief Size of buffer in multiples of elements */
|
||||
DMA_Stream_TypeDef *dma; /**< @brief DMA Stream used to transfer data */
|
||||
size_t get_idx; /**< @brief Get index for SW. Indicates the next element to be read */
|
||||
uint8_t base_dma_id; /**< @brief Id of the DMA controller, the stream belongs to. Either 1 or 2. */
|
||||
size_t element_size; /**< @brief Size of a buffer element (1, 2, or 4 bytes) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA ring buffer for data transfer from memory to peripheral
|
||||
*/
|
||||
struct dma_ring_buffer_to_periph {
|
||||
void *src_buffer; /**< @brief Ring buffer */
|
||||
size_t buffer_count; /**< @brief Size of buffer in multiples of elements */
|
||||
DMA_Stream_TypeDef *dma; /**< @brief DMA Stream used to transfer data */
|
||||
volatile size_t dma_get_idx_current; /**< @brief Current get index of the (not yet) running DMA Stream. */
|
||||
volatile size_t dma_get_idx_future; /**< @brief Get index in the buffer, after the current DMA transfer has finished */
|
||||
volatile size_t sw_put_idx; /**< @brief Put index for software */
|
||||
uint8_t dma_base_id; /**< @brief Id of the DMA controller, the stream belongs to. Either 1 or 2. */
|
||||
size_t element_size; /**< @brief Size of a buffer element (1, 2, or 4 bytes) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize a ring buffer used for transferring data from a peripheral to memory.
|
||||
* @param[in,out] dma_buffer structure representing the newly initialized ring buffer
|
||||
* @param base_dma_id Id of the DMA controller, the stream belongs to. Either 1 or 2
|
||||
* @param[in] dma_stream DMA Stream to use
|
||||
* @param buffer_element_count Size of buffer in elements
|
||||
* @param element_size Size of an element. Either 1, 2, or 4 bytes
|
||||
* @param[in] data_buffer Buffer to operate on
|
||||
* @param[in] src_reg Source register to read data from
|
||||
* @param dma_trigger_channel Trigger channel for DMA stream. Consult reference manual for a valid number.
|
||||
* @note The ring buffers do not have an overrun detection. You have to make sure to empty the buffer in time.
|
||||
* @return Status (0 is ok)
|
||||
*/
|
||||
int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, void *src_reg, uint8_t dma_trigger_channel);
|
||||
|
||||
/**
|
||||
* @brief Get data from a peripheral to memory ring buffer
|
||||
* @param[in] buff Ring buffer structure
|
||||
* @param[out] data_buff Pointer to set to new data. This must not be modified!
|
||||
* @param[out] len Length in elements
|
||||
* @return 0 if successful (data, no data), -1 if error, and 1 if data with wrap around. Call function again in this case to retrieve rest after wrap around.
|
||||
*/
|
||||
int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const void **data_buff, size_t *len);
|
||||
|
||||
/**
|
||||
* @brief Stop the ring buffer operation.
|
||||
* @note The ring buffer loses all its configuration after this call.
|
||||
* @param buff Ring buffer to stop
|
||||
*/
|
||||
void dma_ring_buffer_periph_to_mem_stop(struct dma_ring_buffer_to_mem *buff);
|
||||
|
||||
/**
|
||||
* @brief Initialize ring buffer to streaming data from meory to a peripheral
|
||||
* @param[in,out] dma_buffer DMA ring buffer structure
|
||||
* @param base_dma_id Id of the DMA controller, the stream belongs to. Either 1 or 2
|
||||
* @param[in] dma_stream DMA stream to use
|
||||
* @param buffer_element_count size of ring buffer in elements
|
||||
* @param element_size Size of an element. Either 1, 2, or 4 bytes
|
||||
* @param[in] data_buffer Ring buffer
|
||||
* @param dma_trigger_channel Trigger channel to start DMA. Consult reference manual for values
|
||||
* @param[in] dest_reg Destination register to stream data to
|
||||
* @return 0 if successful
|
||||
*/
|
||||
int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg);
|
||||
|
||||
/**
|
||||
* @brief Insert data into the ring buffer
|
||||
*
|
||||
* This function will try to insert data into the ring buffer. If the buffer is full, it will wait for the buffer to become empty,
|
||||
* until the data fits into the buffer. If the data is larger than the full buffer, it is split. The buffer is fully written. The rest is written after the buffer has emptied out,
|
||||
* until the rest fits in
|
||||
*
|
||||
* @param buff Ring buffer element
|
||||
* @param data_to_insert Data to put in buffer
|
||||
* @param count Element count of data to insert
|
||||
* @return 0 if successful.
|
||||
*/
|
||||
int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Call this function on a transfer complete interrupt of the DMA.
|
||||
* @note It is mandatory to call this function in order to provide a working ring buffer.
|
||||
* @param buff Ring buffer struct
|
||||
*/
|
||||
void dma_ring_buffer_mem_to_periph_int_callback(struct dma_ring_buffer_to_periph *buff);
|
||||
|
||||
/**
|
||||
* @brief Stop the ring buffer operation.
|
||||
* @note The ring buffer loses all its configuration after this call.
|
||||
* @param buff Ring buffer to stop
|
||||
*/
|
||||
void dma_ring_buffer_mem_to_periph_stop(struct dma_ring_buffer_to_periph *buff);
|
||||
|
||||
#endif /* __DMA_RING_BUFFER_H__ */
|
||||
|
||||
|
||||
|
21
stm-firmware/include/stm-periph/stm32-gpio-macros.h
Normal file
21
stm-firmware/include/stm-periph/stm32-gpio-macros.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __STM32GPIOMACROS_H__
|
||||
#define __STM32GPIOMACROS_H__
|
||||
|
||||
#define MODER_DELETE(pin) ~(0x3U << (pin * 2))
|
||||
#define OUTPUT(pin) (0x01U << (pin * 2))
|
||||
#define PULLUP(pin) (0x1U << (pin* 2))
|
||||
#define ALTFUNC(pin) ((0x2) << (pin * 2))
|
||||
#define PINMASK(pin) ((0x3) << (pin * 2))
|
||||
#define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4)
|
||||
#define ANALOG(pin) (0x03 << (pin * 2))
|
||||
|
||||
#define BITMASK_TO_BITNO(x) (x&0x1?0:x&0x2?1:x&0x4?2:x&0x8?3: \
|
||||
x&0x10?4:x&0x20?5:x&0x40?6:x&0x80?7: \
|
||||
x&0x100?8:x&0x200?9:x&0x400?10:x&0x800?11: \
|
||||
x&0x1000?12:x&0x2000?13:x&0x4000?14:x&0x8000?15: \
|
||||
x&0x10000?16:x&0x20000?17:x&0x40000?18:x&0x80000?19: \
|
||||
x&0x100000?20:x&0x200000?21:x&0x400000?22:x&0x800000?23: \
|
||||
x&0x1000000?24:x&0x2000000?25:x&0x4000000?26:x&0x8000000?27: \
|
||||
x&0x10000000?28:x&0x20000000?29:x&0x40000000?30:x&0x80000000?31:32)
|
||||
|
||||
#endif /* __STM32GPIOMACROS_H__ */
|
54
stm-firmware/include/stm-periph/uart.h
Normal file
54
stm-firmware/include/stm-periph/uart.h
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef UART_UART_H_
|
||||
#define UART_UART_H_
|
||||
|
||||
#define UART_RECEIVE_DMA_STREAM DMA2_Stream5
|
||||
|
||||
#define UART_SEND_DMA_STREAM DMA2_Stream7
|
||||
|
||||
#define UART_PERIPH USART1
|
||||
#define UART_RCC_MASK RCC_APB2ENR_USART1EN
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
#define UART_PORT GPIOA
|
||||
#define UART_PORT_RCC_MASK RCC_AHB1ENR_GPIOAEN
|
||||
#define UART_RX_PIN 10
|
||||
#define UART_TX_PIN 9
|
||||
#define UART_RX_PIN_ALTFUNC 7
|
||||
#define UART_TX_PIN_ALTFUNC 7
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
/* UART_DIV is 45.5625 => 115200 @ 84 MHz */
|
||||
#define UART_DIV_FRACTION 9U /* Equals 9/16 = 0.5625 */
|
||||
#define UART_DIV_MANTISSA 45U /* Equals 45 */
|
||||
|
||||
#define UART_BRR_REG_VALUE ((UART_DIV_MANTISSA<<4) | UART_DIV_FRACTION);
|
||||
|
||||
void initUART();
|
||||
void sendChar(char c);
|
||||
void sendString(char* s, int count);
|
||||
|
||||
|
||||
void uart_init_with_dma();
|
||||
|
||||
void uart_disable();
|
||||
|
||||
void uart_send_char(char c);
|
||||
|
||||
void uart_send_array(const char *data, uint32_t len);
|
||||
|
||||
void uart_send_string(const char *string);
|
||||
|
||||
void uart_send_array_with_dma(const char *data, uint32_t len);
|
||||
|
||||
void uart_send_string_with_dma(const char *string);
|
||||
|
||||
int uart_receive_data_with_dma(const char **data, size_t *len);
|
||||
|
||||
|
||||
#endif /* UART_UART_H_ */
|
14
stm-firmware/include/stm-periph/unique-id.h
Normal file
14
stm-firmware/include/stm-periph/unique-id.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __UNIQUE_ID_H__
|
||||
#define __UNIQUE_ID_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Get the device's unique 96 bit ID programmed by ST during manufacturing
|
||||
* @param high high word of ID
|
||||
* @param mid mid word of ID
|
||||
* @param low low word of ID
|
||||
*/
|
||||
void unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low);
|
||||
|
||||
#endif /* __UNIQUE_ID_H__ */
|
@ -1,11 +0,0 @@
|
||||
#ifndef __STM32GPIOMACROS_H__
|
||||
#define __STM32GPIOMACROS_H__
|
||||
|
||||
#define OUTPUT(pin) (0x01U << (pin * 2))
|
||||
#define PULLUP(pin) (0x1U << (pin* 2))
|
||||
#define ALTFUNC(pin) ((0x2) << (pin * 2))
|
||||
#define PINMASK(pin) ((0x3) << (pin * 2))
|
||||
#define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4)
|
||||
#define ANALOG(pin) (0x03 << (pin * 2))
|
||||
|
||||
#endif /* __STM32GPIOMACROS_H__ */
|
@ -181,8 +181,8 @@ typedef enum
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */
|
||||
#include "system_stm32f4xx.h"
|
||||
#include <cmsis/core_cm4.h> /* Cortex-M4 processor and core peripherals */
|
||||
#include <setup/system_stm32f4xx.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @addtogroup Peripheral_registers_structures
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* uart.h
|
||||
*
|
||||
* Created on: Dec 15, 2014
|
||||
* Author: shino-chan
|
||||
*/
|
||||
|
||||
#ifndef UART_UART_H_
|
||||
#define UART_UART_H_
|
||||
|
||||
void initUART();
|
||||
void sendChar(char c);
|
||||
void sendString(char* s, int count);
|
||||
#ifdef _P20N_
|
||||
void yuri();
|
||||
#endif
|
||||
#endif /* UART_UART_H_ */
|
@ -1,126 +1,57 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Created on: Apr 25, 2015
|
||||
* Author: mari
|
||||
*/
|
||||
#include <stm32f4xx.h>
|
||||
#include <systick.h>
|
||||
//#include <arm_math.h>
|
||||
#include <system_stm32f4xx.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <adc-meas.h>
|
||||
/* #include <arm_math.h> */
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <cmsis/core_cm4.h>
|
||||
#include <setup/system_stm32f4xx.h>
|
||||
#include <reflow-controller/systick.h>
|
||||
#include <reflow-controller/adc-meas.h>
|
||||
#include <reflow-controller/shell.h>
|
||||
#include <reflow-controller/digio.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stm-periph/uart.h>
|
||||
|
||||
#define OUTPUT(pin) (0b01 << (pin * 2))
|
||||
#define ANALOG(pin) (0x03 << (pin * 2))
|
||||
|
||||
struct adc_conversions {
|
||||
uint16_t pa2_raw;
|
||||
uint16_t ref_raw;
|
||||
uint16_t temp_raw;
|
||||
uint16_t vbat_raw;
|
||||
};
|
||||
|
||||
static volatile struct adc_conversions adc_results;
|
||||
|
||||
volatile uint64_t sample_count = 0;
|
||||
volatile uint8_t new_data = 0;
|
||||
|
||||
|
||||
void DMA2_Stream0_IRQHandler()
|
||||
static void setup_nvic_priorities()
|
||||
{
|
||||
uint32_t lisr;
|
||||
/* No sub priorities */
|
||||
NVIC_SetPriorityGrouping(2);
|
||||
|
||||
lisr = DMA2->LISR;
|
||||
DMA2->LIFCR = lisr;
|
||||
|
||||
if (lisr & DMA_LISR_TCIF0) {
|
||||
if (new_data)
|
||||
new_data = 2;
|
||||
new_data = 1;
|
||||
sample_count++;
|
||||
|
||||
GPIOB->ODR ^= (1<<3);
|
||||
/* Setup Priorities */
|
||||
NVIC_SetPriority(ADC_IRQn, 2);
|
||||
NVIC_SetPriority(DMA2_Stream0_IRQn, 1);
|
||||
NVIC_SetPriority(DMA2_Stream7_IRQn, 3);
|
||||
}
|
||||
|
||||
}
|
||||
static float pt1000_value;
|
||||
static volatile int pt1000_value_status;
|
||||
|
||||
void setup_dma(void *dest, size_t size)
|
||||
int main()
|
||||
{
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
|
||||
|
||||
DMA2_Stream0->M0AR = (uint32_t)dest;
|
||||
DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
|
||||
DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
|
||||
DMA_SxCR_CIRC | DMA_SxCR_TCIE;
|
||||
DMA2_Stream0->NDTR = size;
|
||||
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
|
||||
|
||||
DMA2_Stream0->CR |= DMA_SxCR_EN;
|
||||
new_data = 0;
|
||||
}
|
||||
|
||||
float ext_lf_corr;
|
||||
|
||||
float temp_lf_corr;
|
||||
|
||||
float ref_lf;
|
||||
float vdd_calculated = 3.3f;
|
||||
|
||||
float vbat_lf_corr;
|
||||
|
||||
|
||||
|
||||
static void setup_timers(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
struct adc_conversions working;
|
||||
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
|
||||
__DSB();
|
||||
GPIOB->MODER = OUTPUT(2) | OUTPUT(3);
|
||||
GPIOA->MODER |= ANALOG(2);
|
||||
GPIOB->ODR |= (1<<2);
|
||||
|
||||
ADC1->SMPR2 = (7U<<(3*2));
|
||||
ADC1->SMPR1 = (7U<<18) | (7U<<21) | (7U<<24);
|
||||
ADC1->SQR1 = (2<<20);
|
||||
ADC1->SQR3 = (2<<0) | (16<<(5*2)) | (17<<(5*1));
|
||||
|
||||
ADC->CCR |= (0x2<<16) | ADC_CCR_TSVREFE;
|
||||
ADC1->CR1 = ADC_CR1_SCAN;
|
||||
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||
|
||||
//while(1);
|
||||
const char *uart_input;
|
||||
size_t uart_input_len;
|
||||
shellmatta_handle_t shell_handle;
|
||||
|
||||
setup_nvic_priorities();
|
||||
systick_setup();
|
||||
|
||||
setup_dma(&adc_results, 3);
|
||||
adc_pt1000_setup_meas();
|
||||
|
||||
ADC1->CR2 |= ADC_CR2_SWSTART;
|
||||
digio_setup_default_all();
|
||||
led_setup();
|
||||
loudspeaker_setup();
|
||||
|
||||
uart_init_with_dma();
|
||||
|
||||
shell_handle = shell_init();
|
||||
|
||||
while(1) {
|
||||
if (!new_data) {
|
||||
continue;
|
||||
pt1000_value_status = adc_pt1000_get_current_resistance(&pt1000_value);
|
||||
|
||||
if (uart_receive_data_with_dma(&uart_input, &uart_input_len) >= 0) {
|
||||
shell_handle_input(shell_handle, uart_input, uart_input_len);
|
||||
}
|
||||
|
||||
|
||||
memcpy(&working, &adc_results, sizeof(adc_results));
|
||||
new_data = 0;
|
||||
//ref_lf = 0.995f * ref_lf + 0.005f * (float)working.ref_raw;
|
||||
//vdd_calculated = ((1.21f * 4096)/ ref_lf);
|
||||
|
||||
//temp_lf_corr = 0.99f * temp_lf_corr + 0.01 * (float)working.temp_raw * vdd_calculated / 2.495f;
|
||||
ext_lf_corr = 0.995f * ext_lf_corr + 0.005f * (float)working.pa2_raw / 4096 * 2500.0f; // * vdd_calculated / 2.495f;
|
||||
|
||||
//vbat_lf_corr = 0.99 * vbat_lf_corr + 0.01 * (float)working.vbat_raw / 4096 * vdd_calculated * 2.0f;
|
||||
//systick_wait_ms(300);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -114,7 +114,7 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "stm32f4xx.h"
|
||||
#include <stm32/stm32f4xx.h>
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -399,7 +399,7 @@ static void SetSysClock(void)
|
||||
RCC->CFGR |= RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till the main PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL)
|
||||
{
|
||||
}
|
||||
}
|
239
stm-firmware/shell.c
Normal file
239
stm-firmware/shell.c
Normal file
@ -0,0 +1,239 @@
|
||||
#include <reflow-controller/shell.h>
|
||||
#include <stm-periph/uart.h>
|
||||
#include <string.h>
|
||||
#include <reflow-controller/adc-meas.h>
|
||||
#include <reflow-controller/digio.h>
|
||||
#include <stdlib.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
#include <reflow-controller/systick.h>
|
||||
#include <stm-periph/unique-id.h>
|
||||
|
||||
#ifndef GIT_VER
|
||||
#define GIT_VER "VERSION NOT SET"
|
||||
#endif
|
||||
|
||||
static shellmatta_instance_t shell;
|
||||
static char shell_buffer[512];
|
||||
static char history_buffer[1024];
|
||||
|
||||
static shellmatta_retCode_t write_shell_callback(const char *data, uint32_t len)
|
||||
{
|
||||
uart_send_array_with_dma(data, len);
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
|
||||
static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
|
||||
const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)arguments;
|
||||
(void)length;
|
||||
uint32_t low_id;
|
||||
uint32_t mid_id;
|
||||
uint32_t high_id;
|
||||
|
||||
unique_id_get(&high_id, &mid_id, &low_id);
|
||||
|
||||
shellmatta_printf(handle, "Reflow Oven Controller Firmware " xstr(GIT_VER) "\r\n"
|
||||
"Compiled: " __DATE__ " at " __TIME__ "\r\n"
|
||||
"Serial: %08X-%08X-%08X", high_id, mid_id, low_id);
|
||||
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
|
||||
static shellmatta_retCode_t shell_cmd_digio_get(const shellmatta_handle_t handle,
|
||||
const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)arguments;
|
||||
(void)length;
|
||||
|
||||
shellmatta_printf(handle,
|
||||
"DIGIO0 DIGIO1 DIGIO2 DIGIO3 LED0 LED1 LS\r\n"
|
||||
"%d %d %d %d %d %d %d\r\n",
|
||||
digio_get(0), digio_get(1), digio_get(2), digio_get(3),
|
||||
led_get(0), led_get(1), loudspeaker_get());
|
||||
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
|
||||
static shellmatta_retCode_t shell_cmd_digio_set(const shellmatta_handle_t handle,
|
||||
const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)length;
|
||||
(void)handle;
|
||||
int num = 100;
|
||||
int state;
|
||||
char buff[64];
|
||||
char *curr_token;
|
||||
|
||||
strncpy(buff, arguments, sizeof(buff));
|
||||
|
||||
curr_token = strtok(buff, " ");
|
||||
curr_token = strtok(NULL, " ");
|
||||
if (!curr_token)
|
||||
return SHELLMATTA_ERROR;
|
||||
|
||||
num = atoi(curr_token);
|
||||
|
||||
if (!curr_token)
|
||||
return SHELLMATTA_ERROR;
|
||||
|
||||
curr_token = strtok(NULL, " ");
|
||||
state = atoi(curr_token);
|
||||
|
||||
if (num < 4 && num >= 0)
|
||||
digio_set(num, state);
|
||||
else if (num >= 4 && num <= 5)
|
||||
led_set(num - 4, state);
|
||||
else if (num == 6)
|
||||
loudspeaker_set(state);
|
||||
else
|
||||
return SHELLMATTA_ERROR;
|
||||
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
|
||||
static shellmatta_retCode_t shell_cmd_pt1000_res(const shellmatta_handle_t handle,
|
||||
const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)arguments;
|
||||
(void)length;
|
||||
float resistance;
|
||||
int pt1000_status;
|
||||
const char *display_status;
|
||||
enum adc_pt1000_error pt1000_flags;
|
||||
const char *status_text[] = {"VALID", "WATCHDOG", "DATA-OVERFLOW", "UNSTABLE"};
|
||||
|
||||
|
||||
display_status = status_text[0];
|
||||
pt1000_status = adc_pt1000_get_current_resistance(&resistance);
|
||||
|
||||
if (pt1000_status == 2) {
|
||||
display_status = status_text[3];
|
||||
} else if (pt1000_status) {
|
||||
pt1000_flags = adc_pt1000_check_error();
|
||||
if (pt1000_flags & ADC_PT1000_WATCHDOG_ERROR)
|
||||
display_status = status_text[1];
|
||||
else if (pt1000_flags & ADC_PT1000_OVERFLOW)
|
||||
display_status = status_text[2];
|
||||
}
|
||||
|
||||
shellmatta_printf(handle, "PT1000 resistance: %.2f Ohm [%s]\r\n", resistance, display_status);
|
||||
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
static shellmatta_retCode_t shell_cmd_clear_error_status(const shellmatta_handle_t handle, const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)arguments;
|
||||
(void)length;
|
||||
(void)handle;
|
||||
|
||||
adc_pt1000_clear_error();
|
||||
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
|
||||
static shellmatta_retCode_t shell_cmd_uptime(const shellmatta_handle_t handle,
|
||||
const char *arguments,
|
||||
uint32_t length)
|
||||
{
|
||||
(void)arguments;
|
||||
(void)length;
|
||||
|
||||
shellmatta_printf(handle, "Uptime: %llu secs", global_tick_ms/1000);
|
||||
return SHELLMATTA_OK;
|
||||
}
|
||||
//typedef struct shellmatta_cmd
|
||||
//{
|
||||
// char *cmd; /**< command name */
|
||||
// char *cmdAlias; /**< command alias */
|
||||
// char *helpText; /**< help text to print in "help" command */
|
||||
// char *usageText; /**< usage text to print on parameter error */
|
||||
// shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
|
||||
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
|
||||
//} shellmatta_cmd_t;
|
||||
|
||||
static shellmatta_cmd_t cmd[6] = {
|
||||
{
|
||||
.cmd = "version",
|
||||
.cmdAlias = "ver",
|
||||
.helpText = "Print firmware version",
|
||||
.usageText = NULL,
|
||||
.cmdFct = shell_cmd_ver,
|
||||
.next = &cmd[1],
|
||||
},
|
||||
{
|
||||
.cmd = "pt1000",
|
||||
.cmdAlias = "pt",
|
||||
.helpText = "Get current filtered and calibrated PT1000 resistance",
|
||||
.usageText = NULL,
|
||||
.cmdFct = shell_cmd_pt1000_res,
|
||||
.next = &cmd[2],
|
||||
},
|
||||
{
|
||||
.cmd = "pt1000-clear-error",
|
||||
.cmdAlias = "pt-clear",
|
||||
.helpText = "Clear error status of PT1000 reading",
|
||||
.usageText = NULL,
|
||||
.cmdFct = shell_cmd_clear_error_status,
|
||||
.next = &cmd[3],
|
||||
},
|
||||
{
|
||||
.cmd = "digio-get",
|
||||
.cmdAlias = "dg",
|
||||
.helpText = "Read all digital input/output ports",
|
||||
.usageText = NULL,
|
||||
.cmdFct = shell_cmd_digio_get,
|
||||
.next = &cmd[4],
|
||||
},
|
||||
{
|
||||
.cmd = "digio-set",
|
||||
.cmdAlias = "ds",
|
||||
.helpText = "Set DIGIO Port",
|
||||
.usageText = "digio-set <num> <state>",
|
||||
.cmdFct = shell_cmd_digio_set,
|
||||
.next = &cmd[5],
|
||||
},
|
||||
{
|
||||
.cmd = "uptime",
|
||||
.cmdAlias = "upt",
|
||||
.helpText = "Get uptime in seconds",
|
||||
.usageText = "",
|
||||
.cmdFct = shell_cmd_uptime,
|
||||
.next = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
shellmatta_handle_t shell_init(void)
|
||||
{
|
||||
shellmatta_handle_t handle;
|
||||
shellmatta_retCode_t ret;
|
||||
|
||||
ret = shellmatta_doInit(&shell, &handle, shell_buffer, sizeof(shell_buffer), history_buffer, sizeof(history_buffer),
|
||||
"\e[1;32mEnter command:\e[m\r\n", cmd, write_shell_callback);
|
||||
if (ret != SHELLMATTA_OK)
|
||||
handle = NULL;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
void shell_handle_input(shellmatta_handle_t shell, const char *data, size_t len)
|
||||
{
|
||||
if (!shell)
|
||||
return;
|
||||
|
||||
shellmatta_processData(shell, (char *)data, (uint32_t)len);
|
||||
}
|
||||
|
||||
void shell_print_string(shellmatta_handle_t shell, const char *string)
|
||||
{
|
||||
if (!shell)
|
||||
return;
|
||||
|
||||
shellmatta_write(shell, (char *)string, strlen(string));
|
||||
}
|
1
stm-firmware/shellmatta
Submodule
1
stm-firmware/shellmatta
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 4dc6cd1e79be4fed928443b91de70699773f7084
|
135
stm-firmware/stm-periph/clock-enable-manager.c
Normal file
135
stm-firmware/stm-periph/clock-enable-manager.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <helper-macros/helper-macros.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct rcc_enable_count {
|
||||
volatile uint32_t *rcc_reg_addr;
|
||||
uint32_t enable_bit_cnt;
|
||||
uint8_t rcc_enable_bit_pos;
|
||||
};
|
||||
|
||||
#if RCC_ENABLE_MANAGER_STATIC
|
||||
|
||||
static struct rcc_enable_count enable_count_list[RCC_ENABLE_MANAGER_COUNT] = {0};
|
||||
|
||||
#else
|
||||
#error "RCC manager with dynamic memory not implemented!"
|
||||
#endif
|
||||
|
||||
#if RCC_ENABLE_MANAGER_STATIC
|
||||
static struct rcc_enable_count *search_enable_entry_in_list(volatile uint32_t *reg_addr, uint8_t bit_pos)
|
||||
{
|
||||
unsigned int i;
|
||||
struct rcc_enable_count *ret_element = NULL;
|
||||
struct rcc_enable_count *current_element;
|
||||
|
||||
for (i = 0; i < COUNT_OF(enable_count_list); i++) {
|
||||
current_element = &enable_count_list[i];
|
||||
|
||||
/* Check if register address and bit position match */
|
||||
if (reg_addr != current_element->rcc_reg_addr)
|
||||
continue;
|
||||
if (bit_pos != current_element->rcc_enable_bit_pos)
|
||||
continue;
|
||||
|
||||
/* Found entry. Wohoo! */
|
||||
ret_element = current_element;
|
||||
}
|
||||
|
||||
return ret_element;
|
||||
}
|
||||
|
||||
static struct rcc_enable_count *enable_entry_list_get_free_entry()
|
||||
{
|
||||
struct rcc_enable_count *ret_ptr = NULL;
|
||||
const int list_len = COUNT_OF(enable_count_list);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < list_len; i++) {
|
||||
if (enable_count_list[i].rcc_reg_addr == NULL) {
|
||||
ret_ptr = &enable_count_list[i];
|
||||
|
||||
/* Clear the count value to be safe */
|
||||
ret_ptr->enable_bit_cnt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
static void enable_entry_list_remove_entry(struct rcc_enable_count *entry)
|
||||
{
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
entry->rcc_reg_addr = NULL;
|
||||
entry->enable_bit_cnt = 0;
|
||||
entry->rcc_enable_bit_pos = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct rcc_enable_count *entry;
|
||||
|
||||
if (!rcc_enable_register || bit_no > 31) {
|
||||
return -1000;
|
||||
}
|
||||
|
||||
/* Enable the clock in any case, no matter what follows */
|
||||
*rcc_enable_register |= (1U<<bit_no);
|
||||
|
||||
/* Check if bit is already in list */
|
||||
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
||||
|
||||
if (!entry) {
|
||||
/* Create ne entry at first free place in list */
|
||||
entry = enable_entry_list_get_free_entry();
|
||||
|
||||
/* Check if entry is valid. If not return */
|
||||
if (!entry) {
|
||||
ret_val = -1;
|
||||
goto ret_error_code;
|
||||
}
|
||||
|
||||
/* Set entry */
|
||||
entry->rcc_reg_addr = rcc_enable_register;
|
||||
entry->rcc_enable_bit_pos = bit_no;
|
||||
}
|
||||
|
||||
/* Increment enable counter */
|
||||
entry->enable_bit_cnt++;
|
||||
|
||||
ret_error_code:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
||||
{
|
||||
int ret_val = -1;
|
||||
struct rcc_enable_count *entry;
|
||||
|
||||
if (!rcc_enable_register || bit_no > 31) {
|
||||
return -1000;
|
||||
}
|
||||
|
||||
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
||||
|
||||
/* If entry is found and has a count of zero, disable clock */
|
||||
if (entry) {
|
||||
/* Found entry => Decrement count and delete if zero */
|
||||
entry->enable_bit_cnt--;
|
||||
if (entry->enable_bit_cnt <= 0) {
|
||||
enable_entry_list_remove_entry(entry);
|
||||
|
||||
/* Disable clock */
|
||||
*rcc_enable_register &= ~(1U<<bit_no);
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
258
stm-firmware/stm-periph/dma-ring-buffer.c
Normal file
258
stm-firmware/stm-periph/dma-ring-buffer.c
Normal file
@ -0,0 +1,258 @@
|
||||
#include <stm-periph/dma-ring-buffer.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en)
|
||||
{
|
||||
int ret_val;
|
||||
int (*clk_func)(volatile uint32_t *, uint8_t);
|
||||
|
||||
if (clk_en)
|
||||
clk_func = rcc_manager_enable_clock;
|
||||
else
|
||||
clk_func = rcc_manager_disable_clock;
|
||||
|
||||
switch (base_dma) {
|
||||
case 1:
|
||||
ret_val = clk_func(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA1EN));
|
||||
break;
|
||||
case 2:
|
||||
ret_val = clk_func(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
||||
break;
|
||||
default:
|
||||
ret_val = -1000;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id,
|
||||
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size,
|
||||
void *data_buffer, void* src_reg, uint8_t dma_trigger_channel)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
if (!dma_buffer || !dma_stream || !data_buffer || !src_reg)
|
||||
return -1000;
|
||||
|
||||
if (dma_trigger_channel > 7)
|
||||
return -1007;
|
||||
|
||||
dma_buffer->base_dma_id = base_dma_id;
|
||||
|
||||
ret_val = dma_ring_buffer_switch_clock_enable(base_dma_id, true);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
dma_buffer->dma = dma_stream;
|
||||
dma_buffer->get_idx = 0;
|
||||
dma_buffer->buffer_count = buffer_element_count;
|
||||
|
||||
dma_buffer->data_ptr = data_buffer;
|
||||
dma_buffer->element_size = element_size;
|
||||
|
||||
dma_stream->PAR = (uint32_t)src_reg;
|
||||
dma_stream->M0AR = (uint32_t)data_buffer;
|
||||
dma_stream->NDTR = buffer_element_count;
|
||||
dma_stream->NDTR = buffer_element_count;
|
||||
|
||||
dma_stream->CR |= (dma_trigger_channel<<25) | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const void **data_buff, size_t *len)
|
||||
{
|
||||
int ret_code = 0;
|
||||
uint32_t ndtr;
|
||||
size_t put_idx;
|
||||
|
||||
if (!buff || !data_buff || !len)
|
||||
return -1;
|
||||
|
||||
|
||||
ndtr = buff->dma->NDTR;
|
||||
put_idx = buff->buffer_count - ndtr;
|
||||
|
||||
/* Check if wrap around */
|
||||
if (put_idx < buff->get_idx) {
|
||||
*data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
|
||||
*len = buff->buffer_count - buff->get_idx;
|
||||
buff->get_idx = 0;
|
||||
ret_code = 1;
|
||||
} else if (put_idx > buff->get_idx) {
|
||||
*data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
|
||||
*len = put_idx - buff->get_idx;
|
||||
buff->get_idx += *len;
|
||||
} else {
|
||||
/* No new data */
|
||||
*len = 0;
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
void dma_ring_buffer_periph_to_mem_stop(struct dma_ring_buffer_to_mem *buff)
|
||||
{
|
||||
if (!buff || !buff->dma)
|
||||
return;
|
||||
|
||||
buff->dma->CR = 0;
|
||||
buff->dma->NDTR = 0;
|
||||
buff->dma->M1AR = 0;
|
||||
buff->dma->FCR = 0;
|
||||
|
||||
dma_ring_buffer_switch_clock_enable(buff->base_dma_id, false);
|
||||
|
||||
memset(buff, 0, sizeof(struct dma_ring_buffer_to_mem));
|
||||
}
|
||||
|
||||
int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg)
|
||||
{
|
||||
if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg)
|
||||
return -1000;
|
||||
|
||||
dma_buffer->dma = dma_stream;
|
||||
dma_buffer->dma_base_id = base_dma_id;
|
||||
dma_buffer->src_buffer = data_buffer;
|
||||
dma_buffer->buffer_count = buffer_element_count;
|
||||
dma_buffer->element_size = element_size;
|
||||
dma_buffer->sw_put_idx = 0U;
|
||||
dma_buffer->dma_get_idx_current = 0U;
|
||||
dma_buffer->dma_get_idx_future = 0U;
|
||||
|
||||
dma_ring_buffer_switch_clock_enable(base_dma_id, true);
|
||||
|
||||
dma_stream->PAR = (uint32_t)dest_reg;
|
||||
dma_stream->CR = DMA_SxCR_MINC | DMA_SxCR_TCIE | (dma_trigger_channel<<25) | DMA_SxCR_DIR_0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_idx, size_t put_idx)
|
||||
{
|
||||
size_t fill_level;
|
||||
|
||||
if (put_idx >= get_idx) {
|
||||
fill_level = (put_idx - get_idx);
|
||||
} else {
|
||||
fill_level = buffer_size - get_idx + put_idx;
|
||||
}
|
||||
|
||||
return fill_level;
|
||||
}
|
||||
|
||||
static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
uint32_t dma_transfer_cnt;
|
||||
|
||||
if (!buff)
|
||||
return;
|
||||
|
||||
/* Check if DMA is running. Do nothing in this case. Will be stated from interrupt */
|
||||
if (buff->dma_get_idx_current != buff->dma_get_idx_future)
|
||||
return;
|
||||
|
||||
/* No new data to transfer */
|
||||
if (buff->sw_put_idx == buff->dma_get_idx_current)
|
||||
return;
|
||||
|
||||
/* Calculate future get idx. Stop at end of buffer to prevent impossible wrap around */
|
||||
if (buff->sw_put_idx < buff->dma_get_idx_current && buff->sw_put_idx != 0) {
|
||||
buff->dma_get_idx_future = 0U;
|
||||
dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current;
|
||||
} else {
|
||||
buff->dma_get_idx_future = buff->sw_put_idx;
|
||||
if (buff->sw_put_idx == 0)
|
||||
dma_transfer_cnt = buff->buffer_count - buff->dma_get_idx_current;
|
||||
else
|
||||
dma_transfer_cnt = buff->sw_put_idx - buff->dma_get_idx_current;
|
||||
}
|
||||
|
||||
buff->dma->NDTR = dma_transfer_cnt;
|
||||
buff->dma->M0AR = (uint32_t)&((char *)buff->src_buffer)[buff->dma_get_idx_current * buff->element_size];
|
||||
buff->dma->CR |= DMA_SxCR_EN;
|
||||
}
|
||||
|
||||
int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t free_item_count;
|
||||
char *insert_ptr;
|
||||
char *dest_ptr;
|
||||
void *ptr;
|
||||
size_t first_round_count;
|
||||
|
||||
if (!buff || !data_to_insert || !count)
|
||||
return -1000;
|
||||
|
||||
/* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest
|
||||
* Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a completely empty one
|
||||
*/
|
||||
if (count >= buff->buffer_count) {
|
||||
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1);
|
||||
if (ret)
|
||||
goto return_retval;
|
||||
ptr = (void *)(((char *)data_to_insert) + ((buff->buffer_count-1) * buff->element_size));
|
||||
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, ptr, count - buff->buffer_count + 1);
|
||||
goto return_retval;
|
||||
}
|
||||
|
||||
/* Wait for buffer to be able to handle input */
|
||||
do {
|
||||
free_item_count = buff->buffer_count - calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, buff->sw_put_idx);
|
||||
} while (free_item_count < count+1);
|
||||
|
||||
/* Fillup buffer (max is buffer end, wrap around afterwards) */
|
||||
insert_ptr = (char *)data_to_insert;
|
||||
dest_ptr = &((char *)buff->src_buffer)[buff->sw_put_idx * buff->element_size];
|
||||
|
||||
/* Check if data completely fits into memory starting from put index */
|
||||
if (buff->buffer_count - buff->sw_put_idx >= count) {
|
||||
/* Copy data and move put index */
|
||||
memcpy(dest_ptr, insert_ptr, buff->element_size * count);
|
||||
buff->sw_put_idx += count;
|
||||
|
||||
/* If buffer is used up to last element, set put index to beginning */
|
||||
if(buff->sw_put_idx >= buff->buffer_count)
|
||||
buff->sw_put_idx = 0;
|
||||
} else {
|
||||
/* Fill up to end of buffer and fill rest after wrap around */
|
||||
first_round_count = buff->element_size * (buff->buffer_count - buff->sw_put_idx);
|
||||
memcpy(dest_ptr, insert_ptr, first_round_count);
|
||||
insert_ptr += first_round_count;
|
||||
memcpy(buff->src_buffer, insert_ptr, count - first_round_count);
|
||||
|
||||
/* Move put index */
|
||||
buff->sw_put_idx = count - first_round_count;
|
||||
}
|
||||
|
||||
/* Queue the DMA transfer. If DMA is already enabled, this has no effect
|
||||
* DMA is triggerd from interrupt in this case
|
||||
*/
|
||||
queue_or_start_dma_transfer(buff);
|
||||
|
||||
return_retval:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dma_ring_buffer_mem_to_periph_int_callback(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
/* update current get index because DMA is finished */
|
||||
buff->dma_get_idx_current = buff->dma_get_idx_future;
|
||||
|
||||
/* Start new DMA transfer if not all data is trasnferred yet */
|
||||
queue_or_start_dma_transfer(buff);
|
||||
}
|
||||
|
||||
void dma_ring_buffer_mem_to_periph_stop(struct dma_ring_buffer_to_periph *buff)
|
||||
{
|
||||
/* Stop DMA and clock */
|
||||
buff->dma->CR = 0;
|
||||
dma_ring_buffer_switch_clock_enable(buff->dma_base_id, false);
|
||||
|
||||
/* Reset the structure */
|
||||
memset(buff, 0, sizeof(struct dma_ring_buffer_to_periph));
|
||||
}
|
101
stm-firmware/stm-periph/uart.c
Normal file
101
stm-firmware/stm-periph/uart.c
Normal file
@ -0,0 +1,101 @@
|
||||
#include <stm-periph/uart.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <stm-periph/clock-enable-manager.h>
|
||||
#include <stm-periph/stm32-gpio-macros.h>
|
||||
#include <stm-periph/dma-ring-buffer.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct dma_ring_buffer_to_mem ring_buff_rx;
|
||||
static struct dma_ring_buffer_to_periph ring_buff_tx;
|
||||
static char uart_rx_buffer[64];
|
||||
static char uart_tx_buffer[256];
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static inline void uart_gpio_config()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(UART_PORT_RCC_MASK));
|
||||
UART_PORT->MODER &= MODER_DELETE(UART_TX_PIN) & MODER_DELETE(UART_RX_PIN);
|
||||
UART_PORT->MODER |= ALTFUNC(UART_RX_PIN) | ALTFUNC(UART_TX_PIN);
|
||||
SETAF(UART_PORT, UART_RX_PIN, UART_RX_PIN_ALTFUNC);
|
||||
SETAF(UART_PORT, UART_TX_PIN, UART_TX_PIN_ALTFUNC);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uart_init_with_dma()
|
||||
{
|
||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(UART_RCC_MASK));
|
||||
#ifdef DEBUGBUILD
|
||||
uart_gpio_config();
|
||||
#endif
|
||||
UART_PERIPH->BRR = UART_BRR_REG_VALUE;
|
||||
UART_PERIPH->CR3 = USART_CR3_DMAR | USART_CR3_DMAT;
|
||||
UART_PERIPH->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||
|
||||
dma_ring_buffer_periph_to_mem_initialize(&ring_buff_rx, 2, UART_RECEIVE_DMA_STREAM, sizeof(uart_rx_buffer), 1U,
|
||||
uart_rx_buffer, (char *)&UART_PERIPH->DR, 4);
|
||||
dma_ring_buffer_mem_to_periph_initialize(&ring_buff_tx, 2, UART_SEND_DMA_STREAM, sizeof(uart_tx_buffer), 1U,
|
||||
uart_tx_buffer, 4U, (void *)&UART_PERIPH->DR);
|
||||
|
||||
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
|
||||
}
|
||||
|
||||
void uart_disable()
|
||||
{
|
||||
UART_PERIPH->CR1 = 0;
|
||||
UART_PERIPH->CR2 = 0;
|
||||
UART_PERIPH->CR3 = 0;
|
||||
dma_ring_buffer_periph_to_mem_stop(&ring_buff_rx);
|
||||
dma_ring_buffer_mem_to_periph_stop(&ring_buff_tx);
|
||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(UART_PORT_RCC_MASK));
|
||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(UART_RCC_MASK));
|
||||
}
|
||||
|
||||
void uart_send_char(char c)
|
||||
{
|
||||
while(!(UART_PERIPH->SR & USART_SR_TXE));
|
||||
UART_PERIPH->DR = c;
|
||||
}
|
||||
|
||||
void uart_send_array(const char *data, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
uart_send_char(data[i]);
|
||||
}
|
||||
|
||||
void uart_send_string(const char *string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; string[i] != '\0'; i++)
|
||||
uart_send_char(string[i]);
|
||||
}
|
||||
|
||||
void uart_send_array_with_dma(const char *data, uint32_t len)
|
||||
{
|
||||
dma_ring_buffer_mem_to_periph_insert_data(&ring_buff_tx, data, len);
|
||||
}
|
||||
|
||||
void uart_send_string_with_dma(const char *string)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(string);
|
||||
uart_send_array_with_dma(string, (uint32_t)len);
|
||||
}
|
||||
|
||||
int uart_receive_data_with_dma(const char **data, size_t *len)
|
||||
{
|
||||
return dma_ring_buffer_periph_to_mem_get_data(&ring_buff_rx, (const void **)data, len);
|
||||
}
|
||||
|
||||
void DMA2_Stream7_IRQHandler()
|
||||
{
|
||||
uint32_t hisr = DMA2->HISR;
|
||||
DMA2->HIFCR = hisr;
|
||||
|
||||
if (hisr & DMA_HISR_TCIF7) {
|
||||
dma_ring_buffer_mem_to_periph_int_callback(&ring_buff_tx);
|
||||
}
|
||||
}
|
15
stm-firmware/stm-periph/unique-id.c
Normal file
15
stm-firmware/stm-periph/unique-id.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stm-periph/unique-id.h>
|
||||
|
||||
#define LOW_WORD_ADDR (0x1FFF7A10UL)
|
||||
#define MID_WORD_ADDR (LOW_WORD_ADDR+4U)
|
||||
#define HIGH_WORD_ADDR (LOW_WORD_ADDR+8U)
|
||||
|
||||
void unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low)
|
||||
{
|
||||
if (!high || !mid || !low)
|
||||
return;
|
||||
|
||||
*low = *((uint32_t *)LOW_WORD_ADDR);
|
||||
*mid = *((uint32_t *)MID_WORD_ADDR);
|
||||
*high = *((uint32_t *)HIGH_WORD_ADDR);
|
||||
}
|
@ -36,8 +36,8 @@ ENTRY(Reset_Handler)
|
||||
_estack = 0x20020000; /* end of 128K RAM on AHB bus*/
|
||||
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0X0000; /* required amount of heap (DEFAULT 0) */
|
||||
_Min_Stack_Size = 0x400 ; /* required amount of stack */
|
||||
_Min_Heap_Size = 0x1500; /* required amount of heap (DEFAULT 0) */
|
||||
_Min_Stack_Size = 0x2000 ; /* required amount of stack */
|
||||
/* recommended min stack size for printf=0x2000, orig = 0x400 */
|
||||
|
||||
/* Specify the memory areas */
|
||||
@ -124,16 +124,10 @@ SECTIONS
|
||||
_sccmram = .; /* create a global symbol at ccmram start */
|
||||
*(.ccmram)
|
||||
*(.ccmram*)
|
||||
|
||||
. = ALIGN(4);
|
||||
_eccmram = .; /* create a global symbol at ccmram end */
|
||||
} >CCM AT> FLASH
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Initialized data sections goes into RAM, load LMA copy after code */
|
||||
@ -143,7 +137,6 @@ SECTIONS
|
||||
_sdata = .; /* create a global symbol at data start */
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
} >RAM AT> FLASH
|
||||
@ -152,7 +145,7 @@ SECTIONS
|
||||
|
||||
/* Uninitialized data section */
|
||||
. = ALIGN(4);
|
||||
.bss :
|
||||
.bss (NOLOAD):
|
||||
{
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_sbss = .; /* define a global symbol at bss start */
|
||||
@ -167,7 +160,7 @@ SECTIONS
|
||||
} >RAM
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough RAM left */
|
||||
._user_heap_stack :
|
||||
._user_heap_stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE (heap_low = .); /* for _sbrk */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <uart/uart.h>
|
||||
#include <stm-periph/uart.h>
|
||||
|
||||
char* _sbrk(int incr) {
|
||||
char* _sbrk(int incr)
|
||||
{
|
||||
extern char heap_low; // Defined by the linker
|
||||
extern char heap_top;
|
||||
static char *heap_end;
|
||||
@ -9,6 +10,7 @@ char* _sbrk(int incr) {
|
||||
if (heap_end == 0) {
|
||||
heap_end = &heap_low;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > &heap_top) {
|
||||
return 0;
|
||||
@ -17,25 +19,46 @@ char* _sbrk(int incr) {
|
||||
heap_end += incr;
|
||||
return (char*) prev_heap_end;
|
||||
}
|
||||
int _isatty(int fd) {
|
||||
|
||||
int _isatty(int fd)
|
||||
{
|
||||
(void)fd;
|
||||
|
||||
return 1;
|
||||
}
|
||||
int _close(int fd) {
|
||||
|
||||
int _close(int fd)
|
||||
{
|
||||
(void)fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int _open(int fd) {
|
||||
|
||||
int _open(int fd)
|
||||
{
|
||||
(void)fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int _fstat(void) {
|
||||
|
||||
int _fstat(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int _lseek(void) {
|
||||
|
||||
int _lseek(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int _read(void) {
|
||||
|
||||
int _read(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int _write(int fd, const void *buf, int count) {
|
||||
sendString((char*)buf, count);
|
||||
|
||||
int _write(int fd, const void *buf, int count)
|
||||
{
|
||||
if (fd == 1)
|
||||
uart_send_array((char*)buf, count);
|
||||
return count;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <systick.h>
|
||||
#include <stm32f4xx.h>
|
||||
#include <core_cm4.h>
|
||||
#include <reflow-controller/systick.h>
|
||||
#include <stm32/stm32f4xx.h>
|
||||
#include <cmsis/core_cm4.h>
|
||||
|
||||
volatile uint32_t wait_tick_ms;
|
||||
volatile uint64_t global_tick_ms;
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* uart.c
|
||||
*
|
||||
* Created on: Dec 15, 2014
|
||||
* Author: shino-chan
|
||||
*/
|
||||
//USART2
|
||||
//PA2 => TX
|
||||
//PA3 => RX
|
||||
//Alternate Function 7
|
||||
#include <uart/uart.h>
|
||||
#include <stm32f4xx.h>
|
||||
|
||||
void initUART() {
|
||||
__DSB();
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
|
||||
__DSB();
|
||||
|
||||
GPIOA->MODER |= (1<<5);
|
||||
GPIOA->AFR[0] |= (7<<8); //Enable Clock
|
||||
GPIOA->MODER |= (1<<5);
|
||||
GPIOA->AFR[0] |= (7<<8);
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
asm("nop");
|
||||
USART2->BRR = 0x1117; //Baudrate 273.4375=>0x1117 9600baud bei 42MHz Periph
|
||||
USART2->CR1 = USART_CR1_UE | USART_CR1_TE;
|
||||
|
||||
}
|
||||
void sendChar(char c) {
|
||||
while(!(USART2->SR & USART_SR_TXE));
|
||||
USART2->DR = c;
|
||||
|
||||
}
|
||||
void sendString(char* s, int count) {
|
||||
int i = 0;
|
||||
for (i = 0; i < count; i++,s++)
|
||||
{
|
||||
if (!(*s))
|
||||
break;
|
||||
sendChar(*s);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user