Skip to content
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### Changes this version:
- Added exponential torque postprocessing for game effects
- Reformatted USB serial string as hex and added command to request UID as hex string
- Added device name to USB Product name
- Added support for F407 OTP section
- Added support for MagnTek MT6835 via SPI (SPI3 port, MagnTek encoder class)

### Changes in 1.16:

Expand All @@ -15,4 +18,5 @@ Internal changes:
- F407: ADC now triggered by timer to reduce interrupt frequency
- Using analog VREF for voltage sensing (better accuracy with unstable 3.3V)
- Added chip temperature readout
- Added remote CAN button/analog source mainclass
- Added remote CAN button/analog source mainclass
- Added exponential torque postprocessing for game effects
42 changes: 42 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# How to contribute

## General terms

1. By contributing to this project you grant the repository owner the full copyright to the contribution.
2. Generally small changes and fixes are more likely to be merged as large changes can easily lead to conflicts in the future.
3. A change in the common codebase must not cause additional issues in target subprojects. It must compile for all subprojects.
4. Changes to pins, interrupts, task priorities, heap/stack sizes must be carefully examined for side effects as they can have unintended consequences in seemingly unrelated modules. Generally do not change these unless absolutely required and tested.
5. Read the [wiki](https://github.com/Ultrawipf/OpenFFBoard/wiki) for additional information about [pinouts](https://github.com/Ultrawipf/OpenFFBoard/wiki/Pinouts-and-peripherals), features, [commands](https://github.com/Ultrawipf/OpenFFBoard/wiki/Commands) and contribution info

### Simplified steps for contribution
1. Clone/Fork the projects master branch
2. Make your changes and create a commit (If it requires GUI features to be changed it is recommended to do the same with the [configurator repo](https://github.com/Ultrawipf/OpenFFBoard-configurator) or if its just a small change detail what the effect is and request a change)
3. Create a pull request for your fork against master and describe your contribution in a detailed way. What bug does it fix? Which feature is added?
4. Wait for approval and append requested changes to your branch
5. Your code gets squash/rebase merged if approved

### Release workflow
Changes should be added in the CHANGELOG.md file.
This will be used to generate release notes.
A tagged commit (v1.x.x) will trigger an automatic release. A tag with a "-" (v1.x.x-beta) generates a prerelease.

A release is triggered when changes are deemed ready for public use.

### Submodules
The configurator is an important part of the project and should be kept up to date with any changes required to support a firmware and the submodule should if possible point to a commit that works with the corresponding firmware version.

Pull the submodules with `git submodule update --init`.

### Branches
If you directly push a branch to the project as a developer your branch name should contain your username or the type of feature. Like `ultrawipf/warpspeed` or `feature/pwmdriver`.
Set your git author name correctly before committing.

### Code style
The code should follow the same style as the other parts of the project and you should use easy to understand comments for complex statements and new functions.

### Flash storage
If you require a variable to be stored in flash check the eeprom emulation functions and choose an address according to `scripts/memory_map.csv` and add it to the list in [`scripts/memory_map.csv`](../../Firmware/scripts/memory_map.csv).

The script `scripts/generate_memory.py` is used to generate `eeprom_addresses.c` and `eeprom_addresses.h` from the csv file to keep track of used addresses and automatically set the right defitions.

In general you should use a block of addresses per class and use the space efficiently. If you have 5 bools and an 8 bit int to store don't use 6 full addresses but pack them into a single uint16_t.
2 changes: 1 addition & 1 deletion Configurator
2 changes: 1 addition & 1 deletion Firmware/FFBoard/Inc/SystemCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "CommandHandler.h"

enum class FFBoardMain_commands : uint32_t{
help=0,save=1,reboot=2,dfu=3,swver=4,hwtype=5,lsmain,main,lsactive,format,errors,errorsclr,flashdump,flashraw,vint,vext,mallinfo,heapfree,taskstats,debug,devid,uid,temp
help=0,save=1,reboot=2,dfu=3,swver=4,hwtype=5,lsmain,main,lsactive,format,errors,errorsclr,flashdump,flashraw,vint,vext,mallinfo,heapfree,taskstats,debug,devid,uid,temp,otp,signature
};

class SystemCommands : public CommandHandler {
Expand Down
11 changes: 10 additions & 1 deletion Firmware/FFBoard/Inc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* For more settings see target_constants.h in a target specific folder
*/

static const uint8_t SW_VERSION_INT[3] = {1,16,4}; // Version as array. 8 bit each!
static const uint8_t SW_VERSION_INT[3] = {1,16,5}; // Version as array. 8 bit each!
#ifndef MAX_AXIS
#define MAX_AXIS 2 // ONLY USE 2 for now else screws HID Reports
#endif
Expand Down Expand Up @@ -99,5 +99,14 @@ static const uint8_t SW_VERSION_INT[3] = {1,16,4}; // Version as array. 8 bit ea
#error "Only TIM_MICROS_HALTICK OR TIM_MICROS may be defined as a microsecond timebase"
#endif

#ifndef SIGNATURELEN
#define SIGNATURELEN 8
#define SIGNATURE
#endif

#if defined(FLASH_OTP_BASE) && defined(FLASH_OTP_END)
#define OTPMEMORY
#endif


#endif
3 changes: 3 additions & 0 deletions Firmware/FFBoard/Inc/flash_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def); // returns
void Flash_Dump(std::vector<std::tuple<uint16_t,uint16_t>> *result,bool includeAll = false);
bool Flash_Format();

bool OTP_Write(uint16_t adroffset,uint64_t dat);
bool OTP_Read(uint16_t adroffset,uint64_t* dat);


template<typename TVal>
inline TVal Flash_ReadDefault(uint16_t adr, TVal def) {
Expand Down
76 changes: 75 additions & 1 deletion Firmware/FFBoard/Src/SystemCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,14 @@ void SystemCommands::registerCommands(){
CommandHandler::registerCommand("devid", FFBoardMain_commands::devid, "Get chip dev id and rev id",CMDFLAG_GET);
CommandHandler::registerCommand("name", CommandHandlerCommands::name, "name of class",CMDFLAG_GET|CMDFLAG_STR_ONLY);
CommandHandler::registerCommand("cmdinfo", CommandHandlerCommands::cmdinfo, "Flags of a command id (adr). -1 if cmd id invalid",CMDFLAG_GETADR);
CommandHandler::registerCommand("uid", FFBoardMain_commands::uid, "Get 96b chip uid. Adr0-2 sel blk",CMDFLAG_GET | CMDFLAG_GETADR);
CommandHandler::registerCommand("uid", FFBoardMain_commands::uid, "Get 96b chip uid. Adr0-2 sel blk",CMDFLAG_GET | CMDFLAG_GETADR | CMDFLAG_INFOSTRING);
CommandHandler::registerCommand("temp", FFBoardMain_commands::temp, "Chip temperature in C",CMDFLAG_GET);
#if defined(OTPMEMORY)
CommandHandler::registerCommand("otp", FFBoardMain_commands::otp, "Access OTP memory",CMDFLAG_GETADR | CMDFLAG_SETADR | CMDFLAG_DEBUG);
#endif
#if defined(SIGNATURE)
CommandHandler::registerCommand("signature", FFBoardMain_commands::signature, "Chip signature in OTP. setadr to write data. set=1 to lock",CMDFLAG_GETADR | CMDFLAG_SETADR | CMDFLAG_GET | CMDFLAG_INFOSTRING);
#endif
}

// Choose lower optimize level because the compiler likes to blow up this function
Expand Down Expand Up @@ -279,13 +285,81 @@ CommandStatus SystemCommands::internalCommand(const ParsedCommand& cmd,std::vect
}else if(cmd.adr == 2){
replies.emplace_back(HAL_GetUIDw2());
}
}else if(cmd.type == CMDtype::info){
char buf[32];
std::snprintf(buf,32,"0x%08lx%08lx%08lx",HAL_GetUIDw2(),HAL_GetUIDw1(),HAL_GetUIDw0()); // Print as hex string
replies.emplace_back(std::string(buf));
}
break;
case FFBoardMain_commands::temp:
{
replies.emplace_back(getChipTemp());
break;
}
#if defined(OTPMEMORY)
case FFBoardMain_commands::otp:
if(cmd.type == CMDtype::setat){
bool success = OTP_Write(cmd.adr, cmd.val);
if(!success){
flag = CommandStatus::ERR;
}
}else if(cmd.type == CMDtype::getat){
CommandReply reply;
reply.type = CommandReplyType::INT;
uint64_t val;
if(OTP_Read(cmd.adr,&val)){
reply.val=val;
}else{
flag = CommandStatus::ERR;
}
replies.push_back(reply);
}
break;
#endif
#if defined(SIGNATURE)
case FFBoardMain_commands::signature:
#if defined(SIGNATURELEN) && defined(SIGBNATUREBASEADR)
if(cmd.type == CMDtype::info){
char buf[(SIGNATURELEN * 16) + 1];
uint64_t dat;
for(uint8_t i = 0;i<SIGNATURELEN;i++){
OTP_Read(SIGBNATUREBASEADR+i, &dat);
std::snprintf(buf+i*16,17,"%016llx",dat); // Print as hex string
}
replies.emplace_back(std::string(buf));
}else if(cmd.type == CMDtype::get){
for(uint8_t i = 0;i<SIGNATURELEN;i++){
uint64_t dat;
OTP_Read(SIGBNATUREBASEADR+i, &dat);
replies.emplace_back(dat,i);
}
}else if(cmd.type == CMDtype::getat){
if(cmd.adr >= SIGNATURELEN || cmd.adr < 0){
flag = CommandStatus::ERR;
}else{
uint64_t dat;
OTP_Read(SIGBNATUREBASEADR+cmd.adr, &dat);
replies.emplace_back(dat,cmd.adr);
}
}else if(cmd.type == CMDtype::setat){
bool success = OTP_Write(cmd.adr+SIGBNATUREBASEADR, cmd.val);
if(!success){
flag = CommandStatus::ERR;
}
}else{
flag = CommandStatus::ERR;
}
#else
if(cmd.type == CMDtype::info){
replies.emplace_back("0");
}else if(cmd.type == CMDtype::get || cmd.type == CMDtype::getat){
replies.emplace_back(0);
}else{
flag = CommandStatus::ERR;
}
#endif
#endif
break;


default:
Expand Down
8 changes: 5 additions & 3 deletions Firmware/FFBoard/Src/USBdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
uint16_t _desc_str[USB_STRING_DESC_BUF_SIZE]; // String buffer

USBdevice::USBdevice(const tusb_desc_device_t* deviceDesc,const uint8_t (*confDesc),const usb_string_desc_t* strings, uint8_t appendSerial) :
Thread("USB", 256, 40), desc_device(deviceDesc), desc_conf(confDesc), string_desc(strings),appendSerial(appendSerial) {
Thread("USB", 330, 40), desc_device(deviceDesc), desc_conf(confDesc), string_desc(strings),appendSerial(appendSerial) {

}

Expand Down Expand Up @@ -41,7 +41,9 @@ void USBdevice::Run(){
* Generates a unique id string from the hardware id
*/
std::string USBdevice::getUsbSerial(){
std::string serial = std::to_string(HAL_GetUIDw0()) + std::to_string(HAL_GetUIDw1()) + std::to_string(HAL_GetUIDw2());
char buf[25];
std::snprintf(buf,25,"%08lx%08lx%08lx",HAL_GetUIDw2(),HAL_GetUIDw1(),HAL_GetUIDw0()); // Print as hex string
std::string serial{buf}; //std::to_string(HAL_GetUIDw0()) + std::to_string(HAL_GetUIDw1()) + std::to_string(HAL_GetUIDw2());

return serial;
}
Expand Down Expand Up @@ -76,7 +78,7 @@ uint16_t* USBdevice::getUsbStringDesc(uint8_t index,uint16_t langid){
field = string_desc->interfaces[index-4];
if(appendSerial){
field += "(";
field.append(getUsbSerial().substr(0, appendSerial));
field.append(std::to_string(HAL_GetUIDw0()).substr(0, appendSerial));
field += ")";
}
}else{
Expand Down
50 changes: 50 additions & 0 deletions Firmware/FFBoard/Src/flash_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,53 @@ void Flash_Dump(std::vector<std::tuple<uint16_t,uint16_t>> *result,bool includeA

}
}


/*
* OTP Helper functions.
* Some chips have internal OTP sections, others may need custom implementations
* Page size and address required
*/
#if defined(FLASH_OTP_BASE) && defined(FLASH_OTP_END) && defined(OTPMEMORY)
// This chip has an OTP section in main flash.

__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
// FLASH_OTP_BASE
// FLASH_OTP_END
uint32_t adr = (FLASH_OTP_BASE+adroffset*sizeof(uint64_t));
if(adr > FLASH_OTP_END){
return false; // Error
}
uint64_t curval = *(uint64_t*)adr;
if(curval != 0xffffffffffffffff){
return false;
}
if(HAL_FLASH_Unlock()!=HAL_OK) return false;
//bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, dat) == HAL_OK;
bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, (uint32_t)(dat)) == HAL_OK;
success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr+4, (uint32_t)(dat >> 32)) == HAL_OK && success;
HAL_FLASH_Lock();
return success;
}


__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
uint32_t adr = (FLASH_OTP_BASE+adroffset*sizeof(uint64_t));
if(adr > FLASH_OTP_END){
return false; // Error
}
uint64_t curval = *(uint64_t*)adr;
*dat = curval;
return true;
}
#else
__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
return false;
}


__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
return false;
}

#endif
23 changes: 16 additions & 7 deletions Firmware/FFBoard/UserExtensions/Inc/MtEncoderSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
#include "CommandHandler.h"
#include "thread.hpp"

#define MAGNTEK_READ 0x80

class MtEncoderSPI: public Encoder, public SPIDevice, public PersistentStorage, public CommandHandler,cpp_freertos::Thread{
enum class MtEncoderSPI_commands : uint32_t{
cspin,pos,errors
cspin,pos,errors,mode
};
enum class MtEncoderSPI_mode : uint8_t{
mt6825,mt6835
};
public:
MtEncoderSPI();
Expand Down Expand Up @@ -51,11 +53,13 @@ class MtEncoderSPI: public Encoder, public SPIDevice, public PersistentStorage,
CommandStatus command(const ParsedCommand& cmd,std::vector<CommandReply>& replies);
void setCsPin(uint8_t cspin);

void setMode(MtEncoderSPI_mode mode);

//bool useDMA = false; // if true uses DMA for angle updates instead of polling SPI. TODO when used with tmc external encoder using DMA will hang the interrupt randomly

private:
uint8_t readSpi(uint8_t addr);
void writeSpi(uint8_t addr,uint8_t data);
uint8_t readSpi(uint16_t addr);
void writeSpi(uint16_t addr,uint8_t data);
void spiTxRxCompleted(SPIPort* port);


Expand All @@ -71,11 +75,16 @@ class MtEncoderSPI: public Encoder, public SPIDevice, public PersistentStorage,
uint32_t errors = 0;


uint8_t txbuf[4] = {0x03 | MAGNTEK_READ,0,0,0};
uint8_t rxbuf[4] = {0,0,0,0};
uint8_t rxbuf_t[4] = {0,0,0,0};
uint8_t txbuf[6] = {0};
uint8_t rxbuf[6] = {0};
uint8_t rxbuf_t[6] = {0};
cpp_freertos::BinarySemaphore requestNewDataSem = cpp_freertos::BinarySemaphore(false);
cpp_freertos::BinarySemaphore waitForUpdateSem = cpp_freertos::BinarySemaphore(false);

MtEncoderSPI_mode mode = MtEncoderSPI_mode::mt6825;

static std::array<uint8_t,256> tableCRC;
const uint8_t POLY = 0x07;
};

#endif /* USEREXTENSIONS_SRC_MTENCODERSPI_H_ */
Expand Down
Loading