initial commit
This commit is contained in:
commit
df732149dd
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.pio
|
||||||
|
CMakeListsPrivate.txt
|
||||||
|
cmake-build-*/
|
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
4
.idea/misc.xml
Normal file
4
.idea/misc.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/untitled.iml" filepath="$PROJECT_DIR$/.idea/untitled.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
2
.idea/untitled.iml
Normal file
2
.idea/untitled.iml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
33
CMakeLists.txt
Normal file
33
CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
|
||||||
|
# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
|
||||||
|
#
|
||||||
|
# If you need to override existing CMake configuration or add extra,
|
||||||
|
# please create `CMakeListsUser.txt` in the root of project.
|
||||||
|
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_C_COMPILER_WORKS 1)
|
||||||
|
set(CMAKE_CXX_COMPILER_WORKS 1)
|
||||||
|
|
||||||
|
project("untitled" C CXX)
|
||||||
|
|
||||||
|
include(CMakeListsPrivate.txt)
|
||||||
|
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
|
||||||
|
include(CMakeListsUser.txt)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
Production ALL
|
||||||
|
COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
Debug ALL
|
||||||
|
COMMAND platformio -c clion debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(Z_DUMMY_TARGET ${SRC_LIST} todo/main_dma.cpp)
|
39
include/README
Normal file
39
include/README
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
46
lib/README
Normal file
46
lib/README
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
20
platformio.ini
Normal file
20
platformio.ini
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:bluepill_f103c8_128k]
|
||||||
|
platform = ststm32
|
||||||
|
board = bluepill_f103c8_128k
|
||||||
|
framework = arduino
|
||||||
|
debug_tool = stlink
|
||||||
|
upload_protocol = stlink
|
||||||
|
build_flags =
|
||||||
|
-ggdb
|
||||||
|
-D USBCON
|
||||||
|
-D USBD_USE_CDC
|
176
src/main.cpp
Normal file
176
src/main.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "stm32f1xx_hal_dma.h"
|
||||||
|
|
||||||
|
#define OUTPIN PA8
|
||||||
|
#define OUTPIN_N PB13
|
||||||
|
#define HVGENPIN PB9
|
||||||
|
|
||||||
|
HardwareTimer *shockTimer;
|
||||||
|
uint32_t shockPwmChannel;
|
||||||
|
uint32_t shockPwmChannel_N;
|
||||||
|
|
||||||
|
HardwareTimer *hvTimer;
|
||||||
|
uint32_t hvPwmChannel;
|
||||||
|
|
||||||
|
uint32_t frequency = 50;
|
||||||
|
uint8_t dutyCycle = 50;
|
||||||
|
uint8_t deadTime = 50;
|
||||||
|
|
||||||
|
uint32_t hvFrequency = 250000;
|
||||||
|
uint8_t hvDutyCycle = 61;
|
||||||
|
/**
|
||||||
|
* output = red, green jumper wire
|
||||||
|
* input = yellow
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
pinMode(PA0, INPUT_ANALOG);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||||
|
|
||||||
|
// https://github.com/ahmetonat/STM32F103-ADC-DMA-example/blob/master/Src/stm32f1xx_hal_msp.c
|
||||||
|
// https://www.stm32duino.com/viewtopic.php?f=41&t=110
|
||||||
|
// https://controllerstech.com/dma-with-adc-using-registers-in-stm32/
|
||||||
|
// https://stm32duinoforum.com/forum/viewtopic_f_48_t_4399.html
|
||||||
|
|
||||||
|
TIM_TypeDef *shockInstance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(OUTPIN), PinMap_PWM);
|
||||||
|
shockPwmChannel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(OUTPIN), PinMap_PWM));
|
||||||
|
shockPwmChannel_N = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(OUTPIN_N), PinMap_PWM));
|
||||||
|
shockTimer = new HardwareTimer(shockInstance);
|
||||||
|
|
||||||
|
TIM_TypeDef *hvInstance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(HVGENPIN), PinMap_PWM);
|
||||||
|
hvPwmChannel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(HVGENPIN), PinMap_PWM));
|
||||||
|
hvTimer = new HardwareTimer(hvInstance);
|
||||||
|
// hvTimer->getHandle()->Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
|
||||||
|
hvTimer->setPWM(hvPwmChannel, HVGENPIN, hvFrequency, hvDutyCycle);
|
||||||
|
|
||||||
|
Serial.begin(0);
|
||||||
|
|
||||||
|
/*shockTimer->pause();
|
||||||
|
shockTimer->setMode(shockPwmChannel, TIMER_OUTPUT_COMPARE_PWM1, OUTPIN);
|
||||||
|
shockTimer->setOverflow(5, HERTZ_FORMAT); // Hertz
|
||||||
|
shockTimer->setCaptureCompare(shockPwmChannel, 50,
|
||||||
|
PERCENT_COMPARE_FORMAT); // 50% Duty Cycle
|
||||||
|
shockTimer->resume(); */
|
||||||
|
|
||||||
|
shockTimer->setMode(shockPwmChannel_N, TIMER_OUTPUT_COMPARE_PWM1, OUTPIN_N);
|
||||||
|
shockTimer->setPWM(shockPwmChannel, OUTPIN, frequency, dutyCycle);
|
||||||
|
TIM1->CCER |= TIM_CCER_CC1NE; // Enable time r1 complementare output (channel 1)
|
||||||
|
|
||||||
|
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.DeadTime = deadTime;
|
||||||
|
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
|
||||||
|
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
|
||||||
|
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
|
||||||
|
HAL_TIMEx_ConfigBreakDeadTime(shockTimer->getHandle(), &sBreakDeadTimeConfig);
|
||||||
|
// LL_TIM_OC_SetDeadTime(TIM1, 50);
|
||||||
|
// shockInstance->BDTR |= 0xFF;
|
||||||
|
|
||||||
|
// with register manipulation, approx 14ns per increment 0 to 128
|
||||||
|
// (DTG Bits 7:0) -> DGT Bit 2|5 = 00100100 = 560ns
|
||||||
|
// bitSet(TIMER1_BASE->BDTR, 2);
|
||||||
|
// bitSet(TIMER1_BASE->BDTR, 5);
|
||||||
|
|
||||||
|
// shockTimer->setPWM(shockPwmChannel, OUTPIN_N, frequency, dutyCycle);
|
||||||
|
// shockTimer->setPWM(shockPwmChannel, OUTPIN_N, frequency, dutyCycle);
|
||||||
|
// setMode(shockPwmChannel, TIMER_, pin);
|
||||||
|
|
||||||
|
/* shockTimer->pause();
|
||||||
|
// TIM1->CCER |= 0x555; //3ch compl enable. 0x55 = 2ch compl enable. 0x5 = 1ch compl enable. As seen on RM0008 pages 353 & 354, CCxNE and CCxE bits
|
||||||
|
TIM1->CCER &= ~TIM_CCER_CC1NP; -- polarity low (or |= to high)
|
||||||
|
TIM1->CCER |= TIM_OCNPOLARITY_HIGH;
|
||||||
|
TIM1->CCER |= 0;
|
||||||
|
TIM1->CCER |= 2;
|
||||||
|
TIM1->CCER |= TIM_CCER_CC1NE;
|
||||||
|
TIM1->CR1 |= TIM_CR1_CMS_1; // center waveform
|
||||||
|
shockTimer->resume(); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRegister(uint8_t reg, uint32_t val) {
|
||||||
|
if (reg == 1) {
|
||||||
|
frequency = val;
|
||||||
|
} else if (reg == 2) {
|
||||||
|
dutyCycle = val;
|
||||||
|
} else if (reg == 3) {
|
||||||
|
hvFrequency = val;
|
||||||
|
} else if (reg == 4) {
|
||||||
|
hvDutyCycle = val;
|
||||||
|
} else if (reg == 5) {
|
||||||
|
deadTime = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg == 1 || reg == 2) {
|
||||||
|
shockTimer->setOverflow(frequency, HERTZ_FORMAT);
|
||||||
|
shockTimer->setCaptureCompare(shockPwmChannel, dutyCycle, PERCENT_COMPARE_FORMAT);
|
||||||
|
} else if (reg == 3 || reg == 4) {
|
||||||
|
hvTimer->setOverflow(hvFrequency, HERTZ_FORMAT);
|
||||||
|
hvTimer->setCaptureCompare(hvPwmChannel, hvDutyCycle, PERCENT_COMPARE_FORMAT);
|
||||||
|
} else if (reg == 5) {
|
||||||
|
LL_TIM_OC_SetDeadTime(TIM1, deadTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* char buffer[256];
|
||||||
|
sprintf(buffer, "Setting register: %d to %d\n", reg, val);
|
||||||
|
Serial.print(buffer); */
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getRegister(uint8_t reg) {
|
||||||
|
if (reg == 1) {
|
||||||
|
return frequency;
|
||||||
|
} else if (reg == 2) {
|
||||||
|
return dutyCycle;
|
||||||
|
} else if (reg == 3) {
|
||||||
|
return hvFrequency;
|
||||||
|
} else if (reg == 4) {
|
||||||
|
return hvDutyCycle;
|
||||||
|
} else if (reg == 5) {
|
||||||
|
return deadTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processSerial() {
|
||||||
|
uint8_t msgType = Serial.read();
|
||||||
|
if (msgType == 1) {
|
||||||
|
// ping
|
||||||
|
uint8_t ack = 0x69;
|
||||||
|
Serial.write((uint8_t*) &ack, sizeof(ack));
|
||||||
|
} else if (msgType == 2) {
|
||||||
|
// set register
|
||||||
|
uint8_t reg = Serial.read();
|
||||||
|
uint32_t buf;
|
||||||
|
Serial.readBytes((char*) &buf, sizeof(buf));
|
||||||
|
setRegister(reg, buf);
|
||||||
|
uint8_t ack = 0x69;
|
||||||
|
Serial.write((uint8_t*) &ack, sizeof(ack));
|
||||||
|
} else if (msgType == 3) {
|
||||||
|
// get register
|
||||||
|
uint8_t reg = Serial.read();
|
||||||
|
uint32_t val = getRegister(reg);
|
||||||
|
// Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
// Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
// uint32_t val = getRegister(reg);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
if (Serial.available()) {
|
||||||
|
processSerial();
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1);
|
||||||
|
}
|
11
test/README
Normal file
11
test/README
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
280
todo/main_dma.cpp
Normal file
280
todo/main_dma.cpp
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "stm32f1xx_ll_dma.h"
|
||||||
|
#include "stm32f1xx_hal_dma.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#define OUTPIN PA8
|
||||||
|
#define OUTPIN_N PB13
|
||||||
|
#define HVGENPIN PB9
|
||||||
|
|
||||||
|
#define M_PI 3.141526535
|
||||||
|
|
||||||
|
HardwareTimer *shockTimer;
|
||||||
|
uint32_t shockPwmChannel;
|
||||||
|
uint32_t shockPwmChannel_N;
|
||||||
|
|
||||||
|
HardwareTimer *hvTimer;
|
||||||
|
uint32_t hvPwmChannel;
|
||||||
|
|
||||||
|
uint32_t frequency = 50;
|
||||||
|
uint8_t dutyCycle = 50;
|
||||||
|
uint8_t deadTime = 50;
|
||||||
|
bool readyToSend = false;
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t hvFrequency = 250000;
|
||||||
|
uint8_t hvDutyCycle = 61;
|
||||||
|
/**
|
||||||
|
* output = red, green jumper wire
|
||||||
|
* input = yellow
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((aligned(4))) volatile uint16_t dmaBuf[] = { /*100, 150, 127, 100*/ 1, 1, 200, 200, 1, 1, 100, 100};
|
||||||
|
size_t dmaBuf_len = sizeof(dmaBuf) / sizeof(dmaBuf[0]);
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
pinMode(PA0, INPUT_ANALOG);
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||||
|
|
||||||
|
// https://github.com/ahmetonat/STM32F103-ADC-DMA-example/blob/master/Src/stm32f1xx_hal_msp.c
|
||||||
|
// https://www.stm32duino.com/viewtopic.php?f=41&t=110
|
||||||
|
// https://controllerstech.com/dma-with-adc-using-registers-in-stm32/
|
||||||
|
// https://stm32duinoforum.com/forum/viewtopic_f_48_t_4399.html
|
||||||
|
|
||||||
|
// DMA:
|
||||||
|
// https://controllerstech.com/pwm-with-dma-in-stm32/ -- good
|
||||||
|
// https://deepbluembedded.com/stm32-change-pwm-duty-cycle-with-dma-for-sine-wave-generation/
|
||||||
|
// https://electronics.stackexchange.com/questions/652738/stm32-pwm-and-output-compare
|
||||||
|
// https://community.st.com/s/question/0D53W000007zeyoSAA/pwm-output-synchronization-problem
|
||||||
|
|
||||||
|
// LL_TIM_OC_SetDeadTime
|
||||||
|
|
||||||
|
|
||||||
|
TIM_TypeDef *shockInstance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(OUTPIN), PinMap_PWM);
|
||||||
|
shockPwmChannel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(OUTPIN), PinMap_PWM));
|
||||||
|
shockPwmChannel_N = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(OUTPIN_N), PinMap_PWM));
|
||||||
|
shockTimer = new HardwareTimer(shockInstance);
|
||||||
|
|
||||||
|
/* TIM_TypeDef *hvInstance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(HVGENPIN), PinMap_PWM);
|
||||||
|
hvPwmChannel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(HVGENPIN), PinMap_PWM));
|
||||||
|
hvTimer = new HardwareTimer(hvInstance); */
|
||||||
|
|
||||||
|
// hvTimer->handle
|
||||||
|
// _timerObj.handle.Init
|
||||||
|
// hvTimer->getHandle()->Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
|
||||||
|
|
||||||
|
Serial.begin(0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < dmaBuf_len; i++) {
|
||||||
|
// dmaBuf[i] = sin(2 * M_PI * i / dmaBuf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*shockTimer->pause();
|
||||||
|
shockTimer->setMode(shockPwmChannel, TIMER_OUTPUT_COMPARE_PWM1, OUTPIN);
|
||||||
|
shockTimer->setOverflow(5, HERTZ_FORMAT); // Hertz
|
||||||
|
shockTimer->setCaptureCompare(shockPwmChannel, 50,
|
||||||
|
PERCENT_COMPARE_FORMAT); // 50% Duty Cycle
|
||||||
|
shockTimer->resume(); */
|
||||||
|
|
||||||
|
shockTimer->setMode(shockPwmChannel_N, TIMER_OUTPUT_COMPARE_PWM1, OUTPIN_N);
|
||||||
|
shockTimer->setPWM(shockPwmChannel, OUTPIN, frequency, dutyCycle);
|
||||||
|
TIM1->CCER |= TIM_CCER_CC1NE;
|
||||||
|
|
||||||
|
|
||||||
|
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.DeadTime = deadTime;
|
||||||
|
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
|
||||||
|
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
|
||||||
|
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
|
||||||
|
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
|
||||||
|
HAL_TIMEx_ConfigBreakDeadTime(shockTimer->getHandle(), &sBreakDeadTimeConfig);
|
||||||
|
// LL_TIM_OC_SetDeadTime(TIM1, 50);
|
||||||
|
// shockInstance->BDTR |= 0xFF;
|
||||||
|
|
||||||
|
|
||||||
|
//Inserts Dead Time approx 14ns per increment 0 to 128
|
||||||
|
//(DTG Bits 7:0)
|
||||||
|
//DGT Bit 2&5 = 00100100 = 560ns
|
||||||
|
// bitSet(TIMER1_BASE->BDTR,2);
|
||||||
|
// bitSet(TIMER1_BASE->BDTR,5);
|
||||||
|
|
||||||
|
//shockTimer->setPWM(shockPwmChannel, OUTPIN_N, frequency, dutyCycle);
|
||||||
|
// shockTimer->setPWM(shockPwmChannel, OUTPIN_N, frequency, dutyCycle);
|
||||||
|
// setMode(shockPwmChannel, TIMER_, pin);
|
||||||
|
|
||||||
|
// hvTimer->setPWM(hvPwmChannel, HVGENPIN, hvFrequency, hvDutyCycle);
|
||||||
|
|
||||||
|
|
||||||
|
// delay(3000);
|
||||||
|
|
||||||
|
/* shockTimer->pause();
|
||||||
|
// TIM1->CCER |= 0x555; //3ch compl enable. 0x55 = 2ch compl enable. 0x5 = 1ch compl enable. As seen on RM0008 pages 353 & 354, CCxNE and CCxE bits
|
||||||
|
TIM1->CCER &= ~TIM_CCER_CC1NP; -- polarity low (or |= to high)
|
||||||
|
TIM1->CCER |= TIM_OCNPOLARITY_HIGH;
|
||||||
|
TIM1->CCER |= 0;
|
||||||
|
TIM1->CCER |= 2;
|
||||||
|
TIM1->CCER |= TIM_CCER_CC1NE;
|
||||||
|
TIM1->CR1 |= TIM_CR1_CMS_1; // center waveform
|
||||||
|
// shockTimer->setPWM(shockPwmChannel, OUTPIN, frequency, dutyCycle);
|
||||||
|
shockTimer->resume(); */
|
||||||
|
|
||||||
|
// auto timerMax = (__HAL_TIM_GET_AUTORELOAD(&(shockTimer->getHandle())) + 1);
|
||||||
|
|
||||||
|
/* for (uint8_t i = 0; i < 200; i++) {
|
||||||
|
angle = ASR*(float)i;
|
||||||
|
IV[i] = (uint16_t) rint(100 + 99*sinf(angle*(PI/180)));
|
||||||
|
} */
|
||||||
|
|
||||||
|
DMA_HandleTypeDef hdma_tim2_ch1;
|
||||||
|
hdma_tim2_ch1.Instance = DMA1_Channel5; // Table 78
|
||||||
|
hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||||
|
hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
|
hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
|
// on an STM32F407 Tim1 is 16bit so DMA transfer needs to be half word, eg Tim2 is 32bit so use word
|
||||||
|
hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||||
|
hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||||
|
hdma_tim2_ch1.Init.Mode = DMA_CIRCULAR;
|
||||||
|
hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_HIGH;
|
||||||
|
|
||||||
|
// HAL_TIM_PWM_DeInit(shockTimer->getHandle());
|
||||||
|
|
||||||
|
if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK) {
|
||||||
|
// Error_Handler();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||||
|
|
||||||
|
// __HAL_LINKDMA(shockTimer->getHandle(), hdma[TIM_DMA_ID_CC1], hdma_tim2_ch1); // TIM_DMA_ID_CC1 -> shockPwmChannel ???
|
||||||
|
|
||||||
|
__HAL_LINKDMA(shockTimer->getHandle(), hdma[TIM_DMA_ID_CC4], hdma_tim2_ch1); // TIM_DMA_ID_CC1 -> shockPwmChannel ???
|
||||||
|
__HAL_LINKDMA(shockTimer->getHandle(), hdma[TIM_DMA_ID_TRIGGER], hdma_tim2_ch1);
|
||||||
|
|
||||||
|
// page 358 Mastering STM32
|
||||||
|
|
||||||
|
// If anyone else is forced by their pinout to use one of the complementary PWM outputs (e.g. CH3N)
|
||||||
|
// then be sure to change the call to HAL_TIM_PWM_Start_DMA() for HAL_TIMEx_PWMN_Start_DMA()
|
||||||
|
// HAL_TIM_PWM_Start_DMA(shockTimer->getHandle(), TIM_CHANNEL_1, (uint32_t*) &dmaBuf, dmaBuf_len);
|
||||||
|
HAL_TIM_PWM_Start_DMA(shockTimer->getHandle(), TIM_CHANNEL_1, (uint32_t*) &dmaBuf[0], dmaBuf_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* LL_DMA_InitTypeDef DMA_InitStruct;
|
||||||
|
DMA_InitStruct.Channel = LL_DMA_CHANNEL_4;
|
||||||
|
DMA_InitStruct.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
|
||||||
|
DMA_InitStruct.MemoryOrM2MDstAddress = (uint32_t)DMA_RX_Buffer;
|
||||||
|
DMA_InitStruct.NbData = DMA_RX_BUFFER_SIZE;
|
||||||
|
DMA_InitStruct.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||||
|
DMA_InitStruct.PeriphOrM2MSrcAddress = (uint32_t)&TIM1->DR;
|
||||||
|
LL_DMA_Init(DMA1, LL_DMA_STREAM_5, &DMA_InitStruct); */
|
||||||
|
|
||||||
|
|
||||||
|
analogReadResolution(12);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShockFrequency(uint32_t freq) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRegister(uint8_t reg, uint32_t val) {
|
||||||
|
if (reg == 1) {
|
||||||
|
frequency = val;
|
||||||
|
} else if (reg == 2) {
|
||||||
|
dutyCycle = val;
|
||||||
|
} else if (reg == 3) {
|
||||||
|
hvFrequency = val;
|
||||||
|
} else if (reg == 4) {
|
||||||
|
hvDutyCycle = val;
|
||||||
|
} else if (reg == 5) {
|
||||||
|
deadTime = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg == 1 || reg == 2) {
|
||||||
|
shockTimer->setOverflow(frequency, HERTZ_FORMAT);
|
||||||
|
shockTimer->setCaptureCompare(shockPwmChannel, dutyCycle, PERCENT_COMPARE_FORMAT);
|
||||||
|
} else if (reg == 3 || reg == 4) {
|
||||||
|
hvTimer->setOverflow(hvFrequency, HERTZ_FORMAT);
|
||||||
|
hvTimer->setCaptureCompare(hvPwmChannel, hvDutyCycle, PERCENT_COMPARE_FORMAT);
|
||||||
|
} else if (reg == 5) {
|
||||||
|
LL_TIM_OC_SetDeadTime(TIM1, deadTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* char buffer[256];
|
||||||
|
sprintf(buffer, "Setting register: %d to %d\n", reg, val);
|
||||||
|
Serial.print(buffer); */
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getRegister(uint8_t reg) {
|
||||||
|
if (reg == 1) {
|
||||||
|
return frequency;
|
||||||
|
} else if (reg == 2) {
|
||||||
|
return dutyCycle;
|
||||||
|
} else if (reg == 3) {
|
||||||
|
return hvFrequency;
|
||||||
|
} else if (reg == 4) {
|
||||||
|
return hvDutyCycle;
|
||||||
|
} else if (reg == 5) {
|
||||||
|
return deadTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void processSerial() {
|
||||||
|
uint8_t msgType = Serial.read();
|
||||||
|
if (msgType == 1) {
|
||||||
|
// ping
|
||||||
|
uint8_t ack = 0x69;
|
||||||
|
Serial.write((uint8_t*) &ack, sizeof(ack));
|
||||||
|
} else if (msgType == 2) {
|
||||||
|
// set register
|
||||||
|
uint8_t reg = Serial.read();
|
||||||
|
uint32_t buf;
|
||||||
|
Serial.readBytes((char*) &buf, sizeof(buf));
|
||||||
|
setRegister(reg, buf);
|
||||||
|
uint8_t ack = 0x69;
|
||||||
|
Serial.write((uint8_t*) &ack, sizeof(ack));
|
||||||
|
} else if (msgType == 3) {
|
||||||
|
// get register
|
||||||
|
uint8_t reg = Serial.read();
|
||||||
|
uint32_t val = getRegister(reg);
|
||||||
|
// Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
// Serial.write((uint8_t*) &val, sizeof(val));
|
||||||
|
// uint32_t val = getRegister(reg);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendMsg(uint8_t type) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
if (Serial.available()) {
|
||||||
|
processSerial();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t v = (uint16_t) analogRead(PA0);
|
||||||
|
// Serial.write((uint8_t*) &v, sizeof(v));
|
||||||
|
/* Serial.print(v);
|
||||||
|
Serial.println(); */
|
||||||
|
delay(1);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user