This section will cover using an ATmega32 with a Modbus RTU connection similar to a VFD Modbus application. So far, I have an RS232 connection from a serial port on the LinuxCNC PC running to a MAX232 based RS232 to TTL converter, then to the ATmega32 serial port. The LinuxCNC software components are a serial Modbus driver based on the gs2_vfd.c driver: http://git.linuxcnc.org/gitweb?p=emc2.git;a=blob;f=src/hal/user_comps/gs2_vfd.c;h=17ed97b78e681c673ab768eb2e0e62bb0b7daf73;hb=e0fbe2669c1bc7b320b738f72ee15abe868aa5a9 , and a set of configuration files to HAL connect the driver pins to a machine application. |
This section will cover using an ATmega32 with a Modbus RTU connection similar to a VFD Modbus application. So far, I have an RS232 connection from a serial port on the LinuxCNC PC running to a MAX232 based RS232 to TTL converter, then to the ATmega32 serial port. The LinuxCNC software components are a serial Modbus driver based on the gs2_vfd.c driver: http://git.linuxcnc.org/gitweb?p=linuxcnc.git;a=blob;f=src/hal/user_comps/gs2_vfd.c;h=17ed97b78e681c673ab768eb2e0e62bb0b7daf73;hb=e0fbe2669c1bc7b320b738f72ee15abe868aa5a9 , and a set of configuration files to HAL connect the driver pins to a machine application. |
The LinuxCNC driver, let's say m32_mbrtu.c , could be made by copying the gs2_vfd.c file linked above to your LinuxCNC subdirectory such as ~/emc2/m32_mbrtu/ . Then copy modbus.c , modbus.h , and Makefile from here: http://git.mah.priv.at/gitweb/vfs11-vfd.git/tree (thanks to Michael Haberler). Rename gs2_vfd.c to m32_mbrtu.c and edit to change the names and variables to match the m32's demo program. Currently, the demo has four 16 bit Input registers starting at register address 1000 (0x03E7) that can be read with Mobus function 4, so the "retval = read_holding_registers(param, slavedata->slave,..." will need to be changed to "retval = read_input_registers(param, slavedata->slave,...". The write function is not needed for the demo program until the demo has writable registers. modbus.c and modbus.h are left alone. The Makefile needs to have every "vfs11_vfd" replaced with "m32_mbrtu", then run "make && sudo make install". If successful, you will have an HAL userspace component that can be loaded in a .hal file with "loadusr m32_mbrtu ..." plus the proper option settings. Next, a LinuxCNC configuration needs to be added to ~/emc2/configs/ and the loadusr added to a .hal file. For testing the pins don't need to be connected because we can see the register values with halmeter or halscope. |
The LinuxCNC driver, let's say m32_mbrtu.c , could be made by copying the gs2_vfd.c file linked above to your LinuxCNC subdirectory such as ~/linuxcnc/m32_mbrtu/ . Then copy modbus.c , modbus.h , and Makefile from here: http://git.mah.priv.at/gitweb/vfs11-vfd.git/tree (thanks to Michael Haberler). Rename gs2_vfd.c to m32_mbrtu.c and edit to change the names and variables to match the m32's demo program. Currently, the demo has four 16 bit Input registers starting at register address 1000 (0x03E7) that can be read with Mobus function 4, so the "retval = read_holding_registers(param, slavedata->slave,..." will need to be changed to "retval = read_input_registers(param, slavedata->slave,...". The write function is not needed for the demo program until the demo has writable registers. modbus.c and modbus.h are left alone. The Makefile needs to have every "vfs11_vfd" replaced with "m32_mbrtu", then run "make && sudo make install". If successful, you will have an HAL userspace component that can be loaded in a .hal file with "loadusr m32_mbrtu ..." plus the proper option settings. Next, a LinuxCNC configuration needs to be added to ~/linuxcnc/configs/ and the loadusr added to a .hal file. For testing the pins don't need to be connected because we can see the register values with halmeter or halscope. |
For the m32 part, download the FreeMODBUS AVR package: http://freemodbus.berlios.de/index.php?idx=5 . I created a m32_mbdemo directory under ~emc2/ to make ~/emc2/m32_mbdemo/, then I copied from the package's linux directory; demo.c, Makefile and /port . demo.c and /port should not need any changes. Makefile needs to have the .cof bits removed, such as remove "$(TARGET).cof" from "all: $(TARGET).elf $(TARGET).cof $(TARGET).hex $(TARGET).eep". cof seems to have something to do with debugging and isn't compatible or essential to this project. "MCU = atmega168" needs to be changed to match the processor being used, "MCU = atmega32" in my case. "CC=...", "OBJCOPY=...", and "AVRDUDE=..." need to be changed to point to the location of these programs on your PC. I used a 10MHz crystal, so I changed "-DF_CPU=20000000UL" to "-DF_CPU=10000000UL", plus changed the fuse bits to match. I believe I removed all of the "../.." because I copied my files to different directory locations. It might be best to try to use the standard locations. The flash section: "flash: $(AVRDUDE) -p m168 -c stk200 -U flash:w:$(TARGET).hex" needs to be changed to match your device and programmer, I used "flash: $(AVRDUDE) -p m32 -c usbtiny -U flash:w:$(TARGET).hex". "make" should compile and create the needed files. "make flash" should upload the hex file to the AVR. It is mentioned in the FreeMODBUS demo documentation that EEPROM is used to store some data, but I didn't see that the EEPROM space was programmed after the upload, and the demo functions, so this is a mystery to me. |
For the m32 part, download the FreeMODBUS AVR package: http://freemodbus.berlios.de/index.php?idx=5 . I created a m32_mbdemo directory under ~/linuxcnc/ to make ~/linuxcnc/m32_mbdemo/, then I copied from the package's linux directory; demo.c, Makefile and /port . demo.c and /port should not need any changes. Makefile needs to have the .cof bits removed, such as remove "$(TARGET).cof" from "all: $(TARGET).elf $(TARGET).cof $(TARGET).hex $(TARGET).eep". cof seems to have something to do with debugging and isn't compatible or essential to this project. "MCU = atmega168" needs to be changed to match the processor being used, "MCU = atmega32" in my case. "CC=...", "OBJCOPY=...", and "AVRDUDE=..." need to be changed to point to the location of these programs on your PC. I used a 10MHz crystal, so I changed "-DF_CPU=20000000UL" to "-DF_CPU=10000000UL", plus changed the fuse bits to match. I believe I removed all of the "../.." because I copied my files to different directory locations. It might be best to try to use the standard locations. The flash section: "flash: $(AVRDUDE) -p m168 -c stk200 -U flash:w:$(TARGET).hex" needs to be changed to match your device and programmer, I used "flash: $(AVRDUDE) -p m32 -c usbtiny -U flash:w:$(TARGET).hex". "make" should compile and create the needed files. "make flash" should upload the hex file to the AVR. It is mentioned in the FreeMODBUS demo documentation that EEPROM is used to store some data, but I didn't see that the EEPROM space was programmed after the upload, and the demo functions, so this is a mystery to me. |
After stating LinuxCNC, the m32_mbrtu component will poll the serial port. This can be verified using a serial port sniffer. I used jpnevulator: http://jpnevulator.snarl.nl/ (warning: one of the options uses an offensive, to me at least, term). jpnevulator seems to need to be started (in its own terminal) before the application being sniffed, so start LinuxCNC after the sniffer. Also transmit and receive need to be connected together (after disconnecting the ATmega somewhere down the line) to loop the Tx back to the Rx, because the sniffer only sniffs the receive input. The sniffer should show something like "0A 04 03 E7 00 04..." repeated as long as LinuxCNC is running. "A0" is the slave ID, 10 in this case. "04" is the Modbus function 4, then two bytes of register address, 1000 or "03 E7" in this case. Then two bytes of the number of registers to send, or 4 in this case. Then two bytes for the packet CRC check sum. This shows what is being sent to the ATmega, but doesn't consider what the ATmega will send back. For that we remove tha Tx Rx jumper and connect the serial cable back on the ATmega. The sniffer should then show the return packets, or some thing like "0A 04 xx xx 00 00 00 00 00 ...". The "xx xx" will be the changing value of register 1. The other registers remain at 0. If you get "0A 84 xx", this the ATmega telling you that there is an error with the exception code of "xx". The codes can be seen here: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf , on page 16 (section 6.4). I used modpoll to fill in for LinuxCNC as a Modbus master during trouble shooting: http://www.modbusdriver.com/modpoll.html . This will show the return register values, but it might also be handy to sniff modpoll to get more details. Just remember to start the sniffer in its own terminal before starting modpoll. |
After starting LinuxCNC, the m32_mbrtu component will poll the serial port. This can be verified using a serial port sniffer. I used jpnevulator: http://jpnevulator.snarl.nl/ (warning: one of the options uses an offensive, to me at least, term). jpnevulator seems to need to be started (in its own terminal) before the application being sniffed, so start LinuxCNC after the sniffer. Also transmit and receive need to be connected together (after disconnecting the ATmega somewhere down the line) to loop the Tx back to the Rx, because the sniffer only sniffs the receive input. The sniffer should show something like "0A 04 03 E7 00 04..." repeated as long as LinuxCNC is running. "A0" is the slave ID, 10 in this case. "04" is the Modbus function 4, then two bytes of register address, 1000 or "03 E7" in this case. Then two bytes of the number of registers to send, or 4 in this case. Then two bytes for the packet CRC check sum. This shows what is being sent to the ATmega, but doesn't consider what the ATmega will send back. For that we remove tha Tx Rx jumper and connect the serial cable back on the ATmega. The sniffer should then show the return packets, or some thing like "0A 04 xx xx 00 00 00 00 00 ...". The "xx xx" will be the changing value of register 1. The other registers remain at 0. If you get "0A 84 xx", this the ATmega telling you that there is an error with the exception code of "xx". The codes can be seen here: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf , on page 16 (section 6.4). I used modpoll to fill in for LinuxCNC as a Modbus master during trouble shooting: http://www.modbusdriver.com/modpoll.html . This will show the return register values, but it might also be handy to sniff modpoll to get more details. Just remember to start the sniffer in its own terminal before starting modpoll. |