|
|
View previous topic :: View next topic |
Author |
Message |
WrySun
Joined: 03 Jan 2023 Posts: 14
|
Porting stepper motor library for TMC2209 driver |
Posted: Tue Jan 03, 2023 3:41 pm |
|
|
I'm trying to port the following library to use a TMC2209 stepper motor driver through UART (not step/dir pins):
https://github.com/terjeio/Trinamic-library
As far as I can tell there is currently no CCS library for the TMC2209 driver (or similar drivers like TMC2208, TMC2130, TMC2660 or A4988), and this Trinamic library is the only C library available for the TMC drivers.
The first issue I run into trying to #include tmc2209.h with CCS 5.0 is a "number of bits out of range" error. It seems that CCS expects the bit fields to be aligned to byte boundaries. Is there any workaround for this issue?
Code: | typedef union {
uint32_t value;
struct {
uint32_t
fclktrim :4,
reserved1 :3,
ottrim :2, // error: number of bits is out of range
reserved :23;
};
} TMC2209_factory_conf_reg_t; |
There are lots and lots of typedefs like this in the tmc2209.h file to conveniently read the configuration registers of the driver, but most of them fail to compile because of this issue. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Jan 03, 2023 4:02 pm |
|
|
my comment.
Yes, could be byte boundary issue.
the third item, would have to 'span' 2 adjacent bytes, probably not allowed.
Just use 'dummy items' with # of bits to make 8.
fclktrim :4,
reserved1 :3,
dummy1 :1, //8th bit needed to make a byte
ortrim :2,
reserved :22;
be sure to reduce the 'reserved' item bits, by any 'dummyx' bits !
Now as I type this, the last reserved is 22 bits and has to span 3 bytes BUT if the compiler stops/halts at the 1st error, you won't see it being wrong....
I've always 'aligned' 8 bits to make a byte, as it seemed 'logical'.
I'm sure others will know, heck it could be a compiler bug ??
Easy enough to change code and test ! |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Tue Jan 03, 2023 4:17 pm |
|
|
Thanks for the reply. The following works in this instance, padding the struct into even bytes:
Code: | uint32_t
fclktrim :4,
reserved1 :3,
ottrim_lo :1,
ottrim_hi :1,
reserved2 :7,
reserved3 :8,
reserved4 :8; |
It's not as convenient to read the bit fields, but it's doable. I'll rewrite the structs and check what issue pops up next. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Jan 04, 2023 1:46 am |
|
|
The register definition as shown is wrong!...
The FCLKTRIM value is actually five bits not four.
Every bit in the register does actually have a meaning. Why not just
make your structure correctly name them all?. Most of the values
(such as FCLKTRIM), are factory set values, but a few are useful for
the driver to know.
I played with this a couple of years ago, and since I set my structure
up to reflect every bit, I didn't have any alignment problems. |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Wed Jan 04, 2023 2:21 am |
|
|
Checking the TMC2209 datasheet, I see that you are absolutely right. The FCLKTRIM is 5 bits, not 4. Seems I can't trust this library to have everything right. Thanks for the insight. |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Thu Jan 12, 2023 11:17 am |
|
|
Some success. I'm now able to compile the C library for the TMC2209 driver with CCS. The library does not include any documentation, comments or example code unfortunately.
With my current set up I can rotate the motor fine with the STEP/DIR pins. I'm now trying to rotate the motor via UART, by writing a velocity value to the VACTUAL registry. This is the simplest way I could think of to test the UART communication.
I have my transmit pin C6 connected to RX pin on the TMC2209 module, and the receive pin C7 connected to TX on the module. MS1 and MS2 pins are grounded, so address of driver becomes 0.
Here is the (simplified) code I'm using to send the stream and write to the VACTUAL registry.
Code: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, stream=PORT1)
//...
// Start rotating the motor (by writing a velocity value to VACTUAL registry)
// Based on TMC2209_WriteRegister() in tmc2209.c
bool TMC2209_Rotate()
{
TMC_uart_write_datagram_t datagram; // struct in common.h made to simplify things
datagram.msg.sync = 0x05; // initial bits used by driver to calibrate baud rate
datagram.msg.slave = 0; // MS1 and MS2 pins are LOW, so address is 0
datagram.msg.addr.value = TMC2209Reg_VACTUAL; // Address for VACTUAL registry (0x22) used to move motor by UART control (datasheet p25)
datagram.msg.addr.write = 1; // this is a "write" not a "read" (last bit of "value" field)
datagram.msg.payload.value = 100; // velocity, microsteps/time
byteswap(datagram.msg.payload.data); // reverse order of these 4 bytes
calcCRC(datagram.data, sizeof(TMC_uart_write_datagram_t)); // populate checksum field
// send write data as an UART string, as specified in TMC2209 datasheet p15
fprintf(PORT1,"%d%d%d%d%d%d%d%d",
datagram.msg.sync,
datagram.msg.slave,
datagram.msg.addr.value,
datagram.msg.payload.data[0],
datagram.msg.payload.data[1],
datagram.msg.payload.data[2],
datagram.msg.payload.data[3],
datagram.msg.crc);
}
void main(void)
{
//... (setup stuff)
TMC2209_t* driver;
TMC2209_SetDefaults(driver); // populate driver struct fields
TMC2209_Init(driver); // write defaults to TMC2209 module
TMC2209_Rotate(); // let's go!
//...
}
|
No rotation occurs when I send this stream so I'm doing something wrong, but not sure what... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Thu Jan 12, 2023 12:10 pm |
|
|
Normally an 'RS-232' communication network will have TTL>RS-232 and RS232-TTL interface devices (MAX232 is one such device.
I had a very quick look at the tmc2209 datasheet and they connect the device directly to the microcomputer.
I suggest adding the 'invert' option to the USE RS232(.....invert .....),recompile and test. This may work, no promises though.
If you have an oscilloscope, attach to the serial line,to confirm th ePIC is transmitting data. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Fri Jan 13, 2023 1:54 am |
|
|
The big problem is he is sending the numbers as decimal ASCII. The chip
expects the numbers as binary. %d codes a byte as ASCII. %c sends the
byte as a 'character' which is what the chip requires......
fprintf(PORT1,"%c%c%c%c%c%c%c%c",
The UART is for direct connection to a micro. It says:
Quote: |
The UART line must be logic high during idle state.
|
Which means it does not want the invert option. |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Fri Jan 13, 2023 3:39 am |
|
|
Thank you so very much to you both! Ttelmah spotted my mistake and the motor started spinning as soon as I changed to %c. You're an absolute lifesaver. Finally some progress. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Fri Jan 13, 2023 7:00 am |
|
|
Brilliant news.
Touch wood you can now progress further.
Have you built the circuitry to allow you to read stuff from the chip as
well as write?. All you need for a single chip, is a 1K resistor between TX
and RX and RX connected to the controller. Your code then has to handle
that it will receive every character you send. The great thing is that you
can then read stuff from the chip as well.
That the wake up is working tells you the checksum calculation is right
and should allow you to start some more powerful controls. |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Mon Jan 16, 2023 1:40 pm |
|
|
I've experimented with all of the write settings of the TMC2209. Even got CoolStep and StallGuard working which are really useful features that I didn't have on the L6470 driver I used before this one.
I cannot for the life of me get reading working. The TMC2209 module I'm using has the 1k ohm resistor integrated and I measure this resistance between the TX and RX pins of the module.
The read function I'm using is very similar to the write function, just that the read request datagram is 4 bytes instead of 8 since it has no data, as per page 16 of the datasheet. To simplify things I've increased the serial buffer size to 12 bytes.
Code: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, stream=PORT1, RECEIVE_BUFFER=12)
// ...
void readDatagram()
{
TMC_uart_read_datagram_t datagram;
uint8_t b[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t count = 0;
datagram.msg.sync = 0x05; // initial bits used by driver to calibrate baud rate
datagram.msg.slave = 0; // MS1 and MS2 pins are LOW, so address is 0
datagram.msg.addr.value = TMC2209Reg_GCONF; // address for GCONF registry (0x00) for general config
datagram.msg.addr.write = 0; // read=0, write=1 (last bit of "value" field)
datagram.msg.crc = calcCRC(datagram.data, sizeof(TMC_uart_read_datagram_t)); // set checksum field
// clear receive buffer
while (kbhit(PORT1)) { fgetc(PORT1); count++; }
// send read datagram
fprintf(PORT1, "%c%c%c%c", datagram.msg.sync, datagram.msg.slave, datagram.msg.addr.value, datagram.msg.crc);
delay_ms(10); // wait for echo and reply bytes
// read all buffered bytes
for(int i = 0; i < 12; i++) {
if (!kbhit(PORT1)) { break; }
b[i] = fgetc(PORT1);
}
sprintf(out_data,"Count: %d, Bytes: %d %d %d %d %d %d %d %d %d %d %d %d", count, b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9],b[10],b[11]);
} |
Output I get is "Count: 0, Bytes: 5 0 2 -113 0 0 0 0 0 0 0 0" so I am receiving the 4 echo bytes, just not the 8 reply bytes.
I've tried connecting my RX pin C7 directly to the TMC2209 module's RX via a 1k ohm resistor, but it gives the same result. I've also tried reading other addresses without any different result. The CRC function works for the write function and is provided in the datasheet so that shouldn't be the issue. I don't have an oscilloscope so can't see the bits. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Tue Jan 17, 2023 11:06 am |
|
|
Your problem is this:
delay_ms(10); // wait for echo and reply bytes
Remember the physical UART only has a couple of characters of buffer.
You are not reading, so everything sent to you, except the last
couple of characters has now been lost!.....
You need to modify the '#use rs232, to enable interrupt driven serial
buffering. Make the buffer large enough to cope with receiving the bytes
being sent as well, and then things have a chance of working. |
|
|
WrySun
Joined: 03 Jan 2023 Posts: 14
|
|
Posted: Wed Jan 18, 2023 2:41 am |
|
|
I've enabled interrupts to get the RECEIVE_BUFFER=12 working. It is able to accurately buffer 12 bytes. If a 13th arrives the buffer is reset to 0 and starts over.
Code: | enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); |
I've tested reading the bytes as they come in one at a time, but it gives me the same result with the 4 echo bytes.
Code: | uint16_t delay = 0;
uint8_t index = 0;
while (delay < 40000) {
if (kbhit(PORT1)) {
b[index] = fgetc(PORT1);
index++;
}
delay_us(1);
delay++;
} |
It seems the driver isn't responding to the datagram. Looking at the sent datagram in binary it is:
00000101 00000000 00000000 01001000
With sync=5, slave address=0, register address+read bit=0 and CRC=72. CRC calculation is taken from the datasheet page 17 so that should be correct. Also, it's working properly for writing data to the driver so I don't think that's the issue. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Jan 18, 2023 9:09 am |
|
|
sigh, it's sooo close to working....
I wonder if you should
send to chip
clear the buffer
wait 9ms
then receive the incoming data
??
my thinking is that since Tx and Rx are tied together with the 1K, Tx data gets sent to the Rx part of the UART.
I'm probably wrong but should be easy to prove.
also, wonder if there's any other users of the chip that READ it ? I see lots SENDING to it...... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Thu Jan 19, 2023 1:54 am |
|
|
I did manage to read it.
Was not using a PIC for this, but the way it was done was that the receive
interrupt routine, was given the count of sent bytes, and it simply read
and threw away each 'sent' byte. What was left was the stuff being
returned. The main code only received these bytes.
Reading is not needed for 90% of stuff. However there are some useful
things like the temperature and load statuses. Also you could read what
current was actually being delivered. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|