6 changed files with 69 additions and 362 deletions
-
3chip/chip.h
-
303components/tmc/ic/TMC5160/TMC5160.c
-
48components/tmc/ic/ztmc5130.cpp
-
61components/tmc/ic/ztmc5130.hpp
-
9hal/zhal_core.cpp
-
7hal/zhal_core.hpp
@ -1,303 +0,0 @@ |
|||
/* |
|||
* TMC5160.c |
|||
* |
|||
* Created on: 03.07.2017 |
|||
* Author: LK |
|||
*/ |
|||
#if 0 |
|||
#include "TMC5160.h" |
|||
|
|||
// => SPI wrapper |
|||
// Send [length] bytes stored in the [data] array over SPI and overwrite [data] |
|||
// with the reply. The first byte sent/received is data[0]. |
|||
extern void tmc5160_readWriteArray(TMC5160TypeDef *tmc5160, uint8_t *data, size_t length); |
|||
// <= SPI wrapper |
|||
static void writeConfiguration(TMC5160TypeDef *tmc5160); |
|||
|
|||
// Writes (x1 << 24) | (x2 << 16) | (x3 << 8) | x4 to the given address |
|||
void tmc5160_writeDatagram(TMC5160TypeDef *tmc5160, uint8_t address, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4) |
|||
{ |
|||
uint8_t data[5] = { address | TMC5160_WRITE_BIT, x1, x2, x3, x4 }; |
|||
tmc5160_readWriteArray(tmc5160, &data[0], 5); |
|||
|
|||
int32_t value = ((uint32_t)x1 << 24) | ((uint32_t)x2 << 16) | (x3 << 8) | x4; |
|||
|
|||
// Write to the shadow register and mark the register dirty |
|||
address = TMC_ADDRESS(address); |
|||
tmc5160->config->shadowRegister[address] = value; |
|||
tmc5160->registerAccess[address] |= TMC_ACCESS_DIRTY; |
|||
} |
|||
|
|||
// Write an integer to the given address |
|||
void tmc5160_writeInt(TMC5160TypeDef *tmc5160, uint8_t address, int32_t value) |
|||
{ |
|||
tmc5160_writeDatagram(tmc5160, address, BYTE(value, 3), BYTE(value, 2), BYTE(value, 1), BYTE(value, 0)); |
|||
} |
|||
|
|||
// Read an integer from the given address |
|||
int32_t tmc5160_readInt(TMC5160TypeDef *tmc5160, uint8_t address) |
|||
{ |
|||
address = TMC_ADDRESS(address); |
|||
|
|||
// register not readable -> shadow register copy |
|||
if(!TMC_IS_READABLE(tmc5160->registerAccess[address])) |
|||
return tmc5160->config->shadowRegister[address]; |
|||
|
|||
uint8_t data[5] = { 0, 0, 0, 0, 0 }; |
|||
|
|||
data[0] = address; |
|||
tmc5160_readWriteArray(tmc5160, &data[0], 5); |
|||
|
|||
data[0] = address; |
|||
tmc5160_readWriteArray(tmc5160, &data[0], 5); |
|||
|
|||
return ((uint32_t)data[1] << 24) | ((uint32_t)data[2] << 16) | (data[3] << 8) | data[4]; |
|||
} |
|||
|
|||
// Initialize a TMC5160 IC. |
|||
// This function requires: |
|||
// - tmc5160: The pointer to a TMC5160TypeDef struct, which represents one IC |
|||
// - channel: The channel index, which will be sent back in the SPI callback |
|||
// - config: A ConfigurationTypeDef struct, which will be used by the IC |
|||
// - registerResetState: An int32_t array with 128 elements. This holds the values to be used for a reset. |
|||
void tmc5160_init(TMC5160TypeDef *tmc5160, uint8_t channel, ConfigurationTypeDef *config, const int32_t *registerResetState) |
|||
{ |
|||
tmc5160->velocity = 0; |
|||
tmc5160->oldTick = 0; |
|||
tmc5160->oldX = 0; |
|||
|
|||
tmc5160->config = config; |
|||
tmc5160->config->callback = NULL; |
|||
tmc5160->config->channel = channel; |
|||
tmc5160->config->configIndex = 0; |
|||
tmc5160->config->state = CONFIG_READY; |
|||
|
|||
size_t i; |
|||
for(i = 0; i < TMC5160_REGISTER_COUNT; i++) |
|||
{ |
|||
tmc5160->registerAccess[i] = tmc5160_defaultRegisterAccess[i]; |
|||
tmc5160->registerResetState[i] = registerResetState[i]; |
|||
} |
|||
} |
|||
|
|||
// Fill the shadow registers of hardware preset non-readable registers |
|||
// Only needed if you want to 'read' those registers e.g to display the value |
|||
// in the TMCL IDE register browser |
|||
void tmc5160_fillShadowRegisters(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
// Check if we have constants defined |
|||
if(ARRAY_SIZE(tmc5160_RegisterConstants) == 0) |
|||
return; |
|||
|
|||
size_t i, j; |
|||
for(i = 0, j = 0; i < TMC5160_REGISTER_COUNT; i++) |
|||
{ |
|||
// We only need to worry about hardware preset, write-only registers |
|||
// that have not yet been written (no dirty bit) here. |
|||
if(tmc5160->registerAccess[i] != TMC_ACCESS_W_PRESET) |
|||
continue; |
|||
|
|||
// Search the constant list for the current address. With the constant |
|||
// list being sorted in ascended order, we can walk through the list |
|||
// until the entry with an address equal or greater than i |
|||
while(j < ARRAY_SIZE(tmc5160_RegisterConstants) && (tmc5160_RegisterConstants[j].address < i)) |
|||
j++; |
|||
|
|||
// Abort when we reach the end of the constant list |
|||
if (j == ARRAY_SIZE(tmc5160_RegisterConstants)) |
|||
break; |
|||
|
|||
// If we have an entry for our current address, write the constant |
|||
if(tmc5160_RegisterConstants[j].address == i) |
|||
{ |
|||
tmc5160->config->shadowRegister[i] = tmc5160_RegisterConstants[j].value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Reset the TMC5160. |
|||
uint8_t tmc5160_reset(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
if(tmc5160->config->state != CONFIG_READY) |
|||
return false; |
|||
|
|||
// Reset the dirty bits and wipe the shadow registers |
|||
size_t i; |
|||
for(i = 0; i < TMC5160_REGISTER_COUNT; i++) |
|||
{ |
|||
tmc5160->registerAccess[i] &= ~TMC_ACCESS_DIRTY; |
|||
tmc5160->config->shadowRegister[i] = 0; |
|||
} |
|||
|
|||
tmc5160->config->state = CONFIG_RESET; |
|||
tmc5160->config->configIndex = 0; |
|||
|
|||
if(tmc5160->config->state != CONFIG_READY){ |
|||
writeConfiguration(tmc5160); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// Restore the TMC5160 to the state stored in the shadow registers. |
|||
// This can be used to recover the IC configuration after a VM power loss. |
|||
uint8_t tmc5160_restore(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
if(tmc5160->config->state != CONFIG_READY) |
|||
return false; |
|||
|
|||
tmc5160->config->state = CONFIG_RESTORE; |
|||
tmc5160->config->configIndex = 0; |
|||
|
|||
if(tmc5160->config->state != CONFIG_READY){ |
|||
writeConfiguration(tmc5160); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// Change the values the IC will be configured with when performing a reset. |
|||
void tmc5160_setRegisterResetState(TMC5160TypeDef *tmc5160, const int32_t *resetState) |
|||
{ |
|||
size_t i; |
|||
for(i = 0; i < TMC5160_REGISTER_COUNT; i++) |
|||
{ |
|||
tmc5160->registerResetState[i] = resetState[i]; |
|||
} |
|||
} |
|||
|
|||
// Register a function to be called after completion of the configuration mechanism |
|||
void tmc5160_setCallback(TMC5160TypeDef *tmc5160, tmc5160_callback callback) |
|||
{ |
|||
tmc5160->config->callback = (tmc_callback_config) callback; |
|||
} |
|||
|
|||
// Helper function: Configure the next register. |
|||
static void writeConfiguration(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
uint8_t *ptr = &tmc5160->config->configIndex; |
|||
const int32_t *settings; |
|||
|
|||
if(tmc5160->config->state == CONFIG_RESTORE) |
|||
{ |
|||
settings = tmc5160->config->shadowRegister; |
|||
// Find the next restorable register |
|||
while((*ptr < TMC5160_REGISTER_COUNT) && !TMC_IS_RESTORABLE(tmc5160->registerAccess[*ptr])) |
|||
{ |
|||
(*ptr)++; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
settings = tmc5160->registerResetState; |
|||
// Find the next resettable register |
|||
while((*ptr < TMC5160_REGISTER_COUNT) && !TMC_IS_RESETTABLE(tmc5160->registerAccess[*ptr])) |
|||
{ |
|||
(*ptr)++; |
|||
} |
|||
} |
|||
|
|||
if(*ptr < TMC5160_REGISTER_COUNT) |
|||
{ |
|||
tmc5160_writeInt(tmc5160, *ptr, settings[*ptr]); |
|||
(*ptr)++; |
|||
} |
|||
else // Finished configuration |
|||
{ |
|||
if(tmc5160->config->callback) |
|||
{ |
|||
((tmc5160_callback)tmc5160->config->callback)(tmc5160, tmc5160->config->state); |
|||
} |
|||
|
|||
tmc5160->config->state = CONFIG_READY; |
|||
} |
|||
} |
|||
|
|||
// Call this periodically |
|||
void tmc5160_periodicJob(TMC5160TypeDef *tmc5160, uint32_t tick) |
|||
{ |
|||
#if 0 |
|||
if(tmc5160->config->state != CONFIG_READY) |
|||
{ |
|||
writeConfiguration(tmc5160); |
|||
return; |
|||
} |
|||
#endif |
|||
|
|||
int32_t XActual; |
|||
uint32_t tickDiff; |
|||
|
|||
// Calculate velocity v = dx/dt |
|||
if((tickDiff = tick - tmc5160->oldTick) >= 5) |
|||
{ |
|||
XActual = tmc5160_readInt(tmc5160, TMC5160_XACTUAL); |
|||
// ToDo CHECK 2: API Compatibility - write alternative algorithm w/o floating point? (LH) |
|||
tmc5160->velocity = (uint32_t) ((float32_t) ((XActual - tmc5160->oldX) / (float32_t) tickDiff) * (float32_t) 1048.576); |
|||
|
|||
tmc5160->oldX = XActual; |
|||
tmc5160->oldTick = tick; |
|||
} |
|||
} |
|||
|
|||
// Rotate with a given velocity (to the right) |
|||
void tmc5160_rotate(TMC5160TypeDef *tmc5160, int32_t velocity) |
|||
{ |
|||
// Set absolute velocity |
|||
tmc5160_writeInt(tmc5160, TMC5160_VMAX, abs(velocity)); |
|||
// Set direction |
|||
tmc5160_writeInt(tmc5160, TMC5160_RAMPMODE, (velocity >= 0) ? TMC5160_MODE_VELPOS : TMC5160_MODE_VELNEG); |
|||
} |
|||
|
|||
// Rotate to the right |
|||
void tmc5160_right(TMC5160TypeDef *tmc5160, uint32_t velocity) |
|||
{ |
|||
tmc5160_rotate(tmc5160, velocity); |
|||
} |
|||
|
|||
// Rotate to the left |
|||
void tmc5160_left(TMC5160TypeDef *tmc5160, uint32_t velocity) |
|||
{ |
|||
tmc5160_rotate(tmc5160, -velocity); |
|||
} |
|||
|
|||
// Stop moving |
|||
void tmc5160_stop(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
tmc5160_rotate(tmc5160, 0); |
|||
} |
|||
|
|||
// Move to a specified position with a given velocity |
|||
void tmc5160_moveTo(TMC5160TypeDef *tmc5160, int32_t position, uint32_t velocityMax) |
|||
{ |
|||
tmc5160_writeInt(tmc5160, TMC5160_RAMPMODE, TMC5160_MODE_POSITION); |
|||
|
|||
// VMAX also holds the target velocity in velocity mode. |
|||
// Re-write the position mode maximum velocity here. |
|||
tmc5160_writeInt(tmc5160, TMC5160_VMAX, velocityMax); |
|||
|
|||
tmc5160_writeInt(tmc5160, TMC5160_XTARGET, position); |
|||
} |
|||
|
|||
// Move by a given amount with a given velocity |
|||
// This function will write the absolute target position to *ticks |
|||
void tmc5160_moveBy(TMC5160TypeDef *tmc5160, int32_t *ticks, uint32_t velocityMax) |
|||
{ |
|||
// determine actual position and add numbers of ticks to move |
|||
*ticks += tmc5160_readInt(tmc5160, TMC5160_XACTUAL); |
|||
|
|||
tmc5160_moveTo(tmc5160, *ticks, velocityMax); |
|||
} |
|||
|
|||
uint8_t tmc5160_consistencyCheck(TMC5160TypeDef *tmc5160) |
|||
{ |
|||
// Config has not yet been written -> it cant be consistent |
|||
if(tmc5160->config->state != CONFIG_READY) |
|||
return 0; |
|||
|
|||
// Check constant shadow registers consistent with actual registers |
|||
for(size_t i = 0; i < TMC5160_REGISTER_COUNT; i++) |
|||
if(tmc5160->config->shadowRegister[i] != tmc5160_readInt(tmc5160, i)) |
|||
return 1; |
|||
|
|||
// No inconsistency detected |
|||
return 0; |
|||
} |
|||
#endif |
Write
Preview
Loading…
Cancel
Save
Reference in new issue