Shop OBEX P1 Docs P2 Docs Learn Events
The Teacup Port - A Work In Progress - 3D Printer Firmware - Page 2 — Parallax Forums

The Teacup Port - A Work In Progress - 3D Printer Firmware

2456789

Comments

  • idbruceidbruce Posts: 6,197
    edited 2015-02-10 17:43
    After going in circles for quite some time, I have decided to get serious about this project. So I am digging in deep, firmly planting my feet, and taking the gloves off.

    My strategy really has not changed much, because I will be starting this new effort, with the same critical core components, which are the DDA filles, the DDA math files, the DDA queue files, the G-Code parser, and the G-Code processor. However, I have also decided to return to the original plan and eliminate conditional compiling. By eliminating the conditional compiling, I will also be eliminating many options offered by the original Teacup firmware. Of course all the options would be nice, but since the original source code is so deeply entrenched in Arduino and AVR support, it would make a complete Propeller port, an extremely daunting task. By porting only the critical components, functional but limited Propeller firmware may be developed for 3D printing. After functional firmware has been developed, other options may be added to enhance the firmware. According to the documentation, ACCELERATION_RAMPING with LOOKAHEAD, appears to be the way to go and that is the type of port that'll be my goal. Additionally, when it comes to parsing the G-Code, I believe the REQUIRE_LINENUMBER and the REQUIRE_CHECKSUM options should be supported, for debugging purposes. As for debugging, there is also the DEBUG option, but this option will initially be unavailable, because the original debug source code will have to be altered to support full duplex serial. However providing DEBUG support should be fairly simple, after the core components are compiling. Until the key components are compiling, all DEBUG source code will be commented out, but left in place, for future reference. When a successful compile is achieved, debugging will then be altered to support full duplex serial and then become available for debugging purposes.

    As you have seen in my previous posts, it was originally my intention, to port Teacup into SPIN, but after long and deep consideration, I have decided to port it in C. There are several reasons for choosing C as the programming language, which I will not discuss, because I don't suppose they are important. I am just letting you all know which direction I am heading. So for a large section of the day, I have been cleaning and editing the key files for this project, making the code more legible, by aligning indents, seperating condtions, adding white space, and removing all conditional compilation. When I have all the files the way I want them, I will then begin to edit out the remaining problems until a successful compilation is achieved. This will include making stub functions as Dave suggested and making sure that all variables and constants are clearly defined.

    Such are my thoughts.

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2015-02-11 14:08
    I did not mention it in my last post, but my port will also include provisions for limit switches on each end of X, Y, and Z axes. While cleaning and editing gcode_process.c, I came across a surprise. The file gcode_process.c relies heavily upon home.c, which provides homing routines for all the axes, providing the limit switches are defined for a given axis. After looking over home.c, it appears that porting that file should be relatively simple. So in addition to the forementioned files, home.c and home.h will now be added, which will provide homing capabilities.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-11 18:27
    Alright, where to begin......

    First off, let me say that I was wrong about a couple things. At this point, I am really beginning to see how important the conditional compilations are to this project. Until just recently, I was under the assumption, that the Teacup settings were a set and forget configuration. The deeper I dig into the source code, the more I realize that the configuration settings are sometimes meant to be just temporary settings, and that this firmware was not intended to be simply a set and forget configuration from jump street. However, I am fairly certain that once you have it tuned, you will rarely have to alter the settings. At first, I saw the conditional compilations as a hinderance, but now I am beginning to see them as an asset. By leaving much of the conditional compilation in place, the firmware can be adaptable to many different types of setups, with each configuration being unique to any given particular machine.

    So upto this point, I have still been spinning my wheels and going nowhere fast. I have wasted a lot of time and useless effort, just getting a grasp of the process and firmware. And I must say that I always find something new and I must admit that it is a very interesting piece of software.

    Anyhow, I got beat up that round and all the previous rounds, but I am not giving up. I just needed to take a few licks, to find out what kind of opponent I was up against. So I will now begin a new round, with conditional compilation.

    As for the necessary files, the list has changed to include several more very important files. The new list is as follows:
      config.default.h
      dda.c
      dda.h
      dda_lookahead.c
      dda_lookahead.h
      dda_maths.c
      dda_maths.h
      dda_queue.c
      dda_queue.h
      gcode_parse.c
      gcode_parse.h
      gcode_process.c
      gcode_process.h
      home.c
      home.h
      pinio.h
      pinio.c

    DING DING

    EDIT: Hopefully it will all fit.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-16 08:20
    Instead of wasting more of my time on useless coding efforts, I have been taking a more in depth look into the Teacup firmware. As mentioned, Arduino and AVR support is wrapped within the software pretty tightly, or at least it appeared that way. After determining the options that I wanted to support, I then began to determine the necessary files to support these options, and then I began to look for the proper location to start inserting Propeller specific code. As it turns out, or so I now believe, the porting process should begin within pinio.h.

    At first glance, or should I say for quite some time, pinio.h seemed a bit overwhelming, and I was having a bit of trouble understanding, the process, the settings, etc... As I see it now, pinio.h sets up the whole runtime environment, by taking the settings established in the config.h file and applying them to functions throughout the firmware, by defining these funtions according to the settings themselves, within the pinio.h file.

    Considering a C port, using SimpleIDE, it appears that pinio.h can be easily altered with the inclusion of simpletools.h. Whereas the READ(s) and WRITE(s) that now exist within pinio.h, could be replaced with functions available from the simpletools library. By replacing these READ(s) and WRITE(s) with simpletools functions, it should define further functions within the firmware that the Teacup frmware needs to operate, thus making a Teacup port actually feasible, without all the additional drudgery of creating stub functions, and writing code that has already been written. Or so I think :)

    Although I have not verified it, I do believe that most of the pins utilized within config.h, are either input or output pins within an Arduino or AVR environment, so there direction does not need to be established, whereas with the Propeller these directions will need to be established, but I have not yet determined the proper location for this. I suppose that if all the pins were being accessed by one cog, everything could be controlled pinio.h. Now I also suppose that cog usage, would also be the determing factor of what should actually be defined in pinio.h, and perhaps there should be files similar to pinio.h for each cog utilized by the necessary pins.

    HMMMM....
  • idbruceidbruce Posts: 6,197
    edited 2015-02-16 18:47
    I am now expanding the discussion of the previous post a bit further.....

    I must admit, even though I am sure it is obvious, that I know zilch about Arduino and I was wrong when I stated,
    Although I have not verified it, I do believe that most of the pins utilized within config.h, are either input or output pins within an Arduino or AVR environment, so there direction does not need to be established

    Upon further digging, I found READ and WRITE defined within arduino.h, which contains several IO macros. So basically, arduino.h is the setup stage for all communication with the various pins utilized. As many of us already know, mendel.c is starting point of Teacup, because it contains the main function. The io_init function of mendel.c relies heavily upon arduino.h, config.h, and pinio.h, for establishing pins utilized, pin directions, pin states, and setting up functions for easily communicating and interfacing with the various pins.

    I mentioned in the previous post that
    Considering a C port, using SimpleIDE, it appears that pinio.h can be easily altered with the inclusion of simpletools.h. Whereas the READ(s) and WRITE(s) that now exist within pinio.h, could be replaced with functions available from the simpletools library. By replacing these READ(s) and WRITE(s) with simpletools functions, it should define further functions within the firmware that the Teacup frmware needs to operate, thus making a Teacup port actually feasible, without all the additional drudgery of creating stub functions, and writing code that has already been written. Or so I think

    While I firmly believe the proceeding statement to be true, this will not affect the use of SET_OUTPUT utilized within mendel.c and pinio.h, because it is defined within arduino.h. By altering both arduino.h and pinio.h to match the functions of the simpletools library, I think a very large portion of the Teacup software can remain as it is.

    EDIT: It almost appears that only the arduino.h file needs to be modified. Wouldn't that be a hoot :)
  • idbruceidbruce Posts: 6,197
    edited 2015-02-16 19:34
    Now expanding upon the two previous posts...

    I am now at a point where I believe the main portion of the port will be the altering of the following code to become Propeller friendly:
    #ifndef		MASK
    /// MASKING- returns \f$2^PIN\f$
    	#define		MASK(PIN)				(1 << PIN)
    #endif
    
    /*
    	magic I/O routines
    
    	now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
    */
    
    /// Read a pin
    #define		_READ(IO)					(IO ## _RPORT & MASK(IO ## _PIN))
    /// write to a pin
    #define		_WRITE(IO, v)			do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
    /// toggle a pin
    #define		_TOGGLE(IO)				do { IO ## _RPORT = MASK(IO ## _PIN); } while (0)
    
    /// set pin as input
    #define		_SET_INPUT(IO)		do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
    /// set pin as output
    #define		_SET_OUTPUT(IO)		do { IO ## _DDR |=  MASK(IO ## _PIN); } while (0)
    
    /// check if pin is an input
    #define		_GET_INPUT(IO)		((IO ## _DDR & MASK(IO ## _PIN)) == 0)
    /// check if pin is an output
    #define		_GET_OUTPUT(IO)		((IO ## _DDR & MASK(IO ## _PIN)) != 0)
    
    Source: Teacup firmware - arduino.h

    EDIT: I could probably use a little help with this, if anyone is so inclined

    EDIT: Here is the funny thing.... And I am sure you will all get a good laugh.... config.h states the following:
    If you want to port this to a new chip, start off with arduino.h and see how you go
    Source: Teacup firmware - config.h


    I read this comment numerous times, but I just did not understand where to begin. After a lot of research and studying of the firmware, now I understand :)

    EDIT: In an effort to provide an easier understanding, I have altered the code above as follows:
    #define MASK(PIN) (1 << PIN)
    
    
    /// Read a pin
    #define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
    
    
    /// write to a pin
    #define _WRITE(IO, v)
    	do
    	{ 
    		if(v)
    		{
    			IO ## _WPORT |= MASK(IO ## _PIN);
    		}
    		
    		else
    		{
    			IO ## _WPORT &= ~MASK(IO ## _PIN);
    		};
    	}	
    	while (0)
    
    
    /// toggle a pin
    #define _TOGGLE(IO)
    	do
    	{
    		IO ## _RPORT = MASK(IO ## _PIN);
    	}
    	while (0)
    
    
    /// set pin as input
    #define _SET_INPUT(IO)
    	do
    	{
    		IO ## _DDR &= ~MASK(IO ## _PIN);
    	}
    	while (0)
    
    
    /// set pin as output
    #define	_SET_OUTPUT(IO)
    	do
    	{
    		IO ## _DDR |=  MASK(IO ## _PIN);
    	}
    	while (0)
    
    
    /// check if pin is an input
    #define _GET_INPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) == 0)
    
    
    /// check if pin is an output
    #define _GET_OUTPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) != 0)
    
    Source: Teacup firmware - arduino.h
  • idbruceidbruce Posts: 6,197
    edited 2015-02-16 21:42
    Now expanding upon the three previous posts...

    After further examination and considering the unknowns of the macros defined within arduino.h, I am now inclined to believe that a modification of pinio.h would be the easiest alternative for porting. In addition to pinio.h, there are several other locations within the Teacup firmware, where the READ and WRITE functions are utilized, as well as some of the additional functions provided by arduino.h. I do believe a Propeller port would be much easier to understand, if all these existing functions were changed to simpletools.h functions, where they are being used.

    EDIT: Although I am uncertain how these alterations will affect the program size, when defined or included in multiple locations.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-02-17 04:44
    Bruce, I think you can simplify the macro definitions to the following:
    #define MASK(PIN)        (1 << PIN)
    #define _READ(IO)       ((INA & MASK(IO ## _PIN)) != 0)
    #define _WRITE(IO, v)   OUTA = (OUTA & ~MASK(IO ## _PIN)) | ((v & 1) << (IO ## _PIN))
    #define _TOGGLE(IO)     OUTA ^= MASK(IO ## _PIN)
    #define _SET_INPUT(IO)  DIRA &= MASK(IO ## _PIN)
    #define _SET_OUTPUT(IO) DIRA |= MASK(IO ## _PIN)
    #define _GET_INPUT(IO)  ((DIRA & MASK(IO ## _PIN)) == 0) 
    #define _GET_OUTPUT(IO) ((DIRA & MASK(IO ## _PIN)) != 0) 
    
    This assumes that the value passed to _WRITE() is either 1 or 0. If not, this value would need to be and'ed with 1.

    The _READ macro returns the bit value at its position in the I/O register. If it needs to return 1 or 0 the macro should be appended with "!= 0".
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 05:31
    Dave

    Thanks for the reply and effort.

    By the time I got back here I had already written something up, but I am unsure of it.

    In the past, I normally just used defines for assigning constant values, so I am unsure if the following would work, because it utilizes functions, but I think it will. Anyhow, I believe something similar to the following is the key to porting this monster.

    Most of these calls are made from either mendel.c or pinio.h, with very few exceptions. And providing this code is acceptable, all references of "#include arduino.h" should be changed to "#include PropelledTeacup.h", or completely removed. Additionally, all references to the simulator, avr, or arduino specific code should be obliterated.
    #include "simpletools.h"
    
    /////////////////////////////////////////////////
    // Propeller Specific
    /////////////////////////////////////////////////
    /// Read a pin
    #define _READ(IO)				get_output(IO)
    
    /// Write to a pin
    #define _WRITE(IO, v)			set_output(IO, v)
    
    /// set pin as input
    #define _SET_INPUT(IO)			set_direction(IO, 0)
    
    /// set pin as output
    #define _SET_OUTPUT(IO)			set_direction(IO, 1)
    /////////////////////////////////////////////////
    /// Read a pin wrapper
    #define READ(IO)				_READ(IO)
    
    /// Write to a pin wrapper
    #define WRITE(IO, v)			_WRITE(IO, v)
    
    /// set pin as input wrapper
    #define SET_INPUT(IO)			_SET_INPUT(IO)
    
    /// set pin as output wrapper
    #define SET_OUTPUT(IO)			_SET_OUTPUT(IO)
    /////////////////////////////////////////////////
    #ifndef BSS
      #define BSS __attribute__ ((__section__ (".bss")))
    #endif
    

    EDIT: I will try both of them. I believe your macros would leave a much smaller footprint, because if I am not mistaken, that would only require the include of propeller.h.

    EDIT: Additionally, I have discovered that _TOGGLE(IO), _GET_INPUT(IO), and _GET_OUTPUT(IO) are unnecessary.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 06:55
    Here is a header file that includes the macros that Dave altered. Even though _TOGGLE(IO), _GET_INPUT(IO), and _GET_OUTPUT(IO) are not used within the Teacup firmware (or at least in the files that I intend to use), I have decided to retain them, because these macros and functions may become useful during the port. This header file only requires the include of propeller.h, whereas the previous header file required simpletools.h. As with the previous header file, all references to the simulator, avr, or arduino specific code should be obliterated.

    Additionally, this file is named PropellerizedTeacup.h
    /*!
    	\file
    	\brief pin definitions and I/O macros
    */
    
    #ifndef	_PROPELLERIZEDTEACUP_H
    #define	_PROPELLERIZEDTEACUP_H
    
    #include <propeller.h>
    
    #ifndef BSS
    	#define BSS __attribute__ ((__section__ (".bss")))
    #endif
    
    #ifndef MASK
    /// MASKING- returns \f$2^PIN\f$
    	#define		MASK(PIN)				(1 << PIN)
    #endif
    
    /*
    	magic I/O routines
    
    	now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
    */
    
    /// Read a pin
    #define _READ(IO)       ((INA & MASK(IO ## _PIN)) != 0)
    
    /// Write to a pin
    #define _WRITE(IO, v)   OUTA = (OUTA & ~MASK(IO ## _PIN)) | ((v & 1) << (IO ## _PIN))
    
    /// toggle a pin
    #define _TOGGLE(IO)     OUTA ^= MASK(IO ## _PIN)
    
    /// set pin as input
    #define _SET_INPUT(IO)  DIRA &= MASK(IO ## _PIN)
    
    /// set pin as output
    #define _SET_OUTPUT(IO) DIRA |= MASK(IO ## _PIN)
    
    /// check if pin is an input
    #define _GET_INPUT(IO)  ((DIRA & MASK(IO ## _PIN)) == 0) 
    
    /// check if pin is an output
    #define _GET_OUTPUT(IO) ((DIRA & MASK(IO ## _PIN)) != 0)
    
    // why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
    
    /// Read a pin wrapper
    #define READ(IO)		_READ(IO)
    
    /// Write to a pin wrapper
    #define WRITE(IO, v)	_WRITE(IO, v)
    
    /// toggle a pin wrapper
    #define TOGGLE(IO)		_TOGGLE(IO)
    
    /// set pin as input wrapper
    #define SET_INPUT(IO)	_SET_INPUT(IO)
    
    /// set pin as output wrapper
    #define SET_OUTPUT(IO)	_SET_OUTPUT(IO)
    
    /// check if pin is an input wrapper
    #define GET_INPUT(IO)	_GET_INPUT(IO)
    
    /// check if pin is an output wrapper
    #define GET_OUTPUT(IO)	_GET_OUTPUT(IO)
    
    #endif /* _PROPELLERIZEDTEACUP_H */
    
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 08:55
    Just a few words to establish my direction....

    As I learn about various aspects of the Teacup firmware and as time passes, my goals of this project have changed significantly, or should I say for the time being.

    As mentioned, I know nothing about Arduino, so without spending a bunch of time learning about Arduino or unless someone takes the time to educate me, all I can do is make various assumptions. At this current point of time, I am assuming that the Teacup firmware is a single threaded process, that runs without the benefit 8 cogs, or even two parallel processes, mostly because of my lack of knowledge about Arduino and the lack of evidence throughout the firmware, but I could be wrong.

    Anyhow, my current goal is to match the operation of Teacup, without taking advantage of all the Propellers attributes. If I can manage that task, then I will see about altering some code to make better use of the Propeller's resources. However this may change as my efforts develop. Of course there are a few exceptions, such as some name changes for the various files, but most of them will remain the same for easy reference, at least for now. However, right from the start, I will be renaming mendel.c to forger.c, to represent the name of the 3D printer prototype that I am building. If I succeed with this port, I will then be referring to the firmware, as the Forger Firmware. As previously mentioned, and please do not forget, my efforts will be geared towards the controller described within this thread: http://forums.parallax.com/showthread.php/155404-Input-Needed-Combining-Propeller-Proto-Board-Prop-DIP-40-and-ADC-for-3D-Printer. However, I am fairly certain that various configurations may be obtained by altering config.h.

    With the assistance of Dave Hein, PropellerizedTeacup.h now exists. This file is intended to replace arduino.h, and this file is responsible for all pin settings and communication with the various IO pins that are utilized. Additionally, PropellerizedTeacup.h should allow for a fair amount of conditional compiling of the Teacup firmware for the Propeller.

    As I see it now, the biggest remaining obstacle is the serial interface, which includes DEBUG, and it is intermingled throughout a large portion of the files. Before proceeding any futher, I will try determine what must be done to remove this huge obstacle, but it may not be as big of a problem as I believe it is.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 09:30
    Just in case anyone is silently following along and in reference to my previous post, the following list and attachment, contains references to the various serial interfaces of Teacup. And these references are just from the files that I may support. As you can clearly see, the serial interfaces are widespread.
    #include "sermsg.h"
    	dda.c
    	dda_lookahead.c
    	dda_queue.c
    	gcode_parse.c
    	gcode_process.c
    	mendel.c
    	sermsg.c
    	sersendf.c
    
    #include "sersendf.h"
    	clock.c
    	dda.c
    	dda_lookahead.c
    	dda_queue.c
    	gcode_parse.c
    	gcode_process.c
    	heater.c
    	mendel.c
    	sersendf.c
    	temp.c
    
    #include "serial.h"
    	clock.c
    	dda.c
    	dda_lookahead.c
    	dda_queue.c
    	gcode_parse.c
    	gcode_process.c
    	mendel.c
    	serial.c
    	sermsg.c
    	sersendf.c
    
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 11:00
    Referring to my last two posts concerning the serial interfaces.....

    Although I am not 100% certain, I am fairly certain that sermsg.h, sermsg.c, sersendf.h, and sersendf.c, can pretty much remain the way they are, with the following exceptions:
      change all references of #include "serial.h" to #include <fdserial.h>
      change all references of serial_writechar(uint8_t data) to fdserial_txChar (fdserial *term, int txbyte)

    Someone please correct me if I am wrong :)

    EDIT: However I am now thinking that this might be a better alternative
      change all references of #include "serial.h" to #include "simpletext.h"
      change all references of serial_writechar(uint8_t data) to putChar (char c)

    EDIT: This was certainly a case of wishful thinking :)
    EDIT: I just got sersend to output to the SimpleIDE terminal the following: sersendf_P(PSTR("rs N%ld Expected line number %ld\n"), 100, 200); :)
  • idbruceidbruce Posts: 6,197
    edited 2015-02-17 19:08
    Alrighty folks, like everyone else, I have my strengths and weaknesses, and this is especially true when it comes to programming. Undoubtedly, there will be times during this project when I need help and this just happens to be another one of those times, because bit banging, bit shifting, and serial communication was never my expertise.

    As I have mentioned in a few of my previous posts, I am now attempting to tackle the serial interface problems. I believe this is probably this biggest problem remaining, besides getting rid of all the interrupt stuff, and I know I will also need help with that to.

    Anyhow, I have been attempting to get certain Teacup serial interface files to communicate with the simpletext library, and I have had partial success. Of course, partial success just won't cut the mustard.

    In an effort to obtain some help and perhaps gain a little more traction with this project, I have created a SimpleIDE project, which should contain a solution to the serial interface problems associated with the Teacup port. However there are still problems to be resolved, as can be witnessed by the attached image.

    Any and all effort that you may be willing to share to make the attached SimpleIDE project bulletproof, will be greatly appreciated.

    EDIT: Please note that the following define can be removed from sersendf.h of the attached project, because it is not needed: #define pgm_read_word(x) (*((uint16_t *)(x)))


    attachment.php?attachmentid=113219&d=1424228891
    672 x 514 - 109K
  • idbruceidbruce Posts: 6,197
    edited 2015-02-18 05:03
    Referring to my previous post....

    All of the build warnings from the attached project, appear to be a result of calls made to GET_ARG within sersendf.c
    #define GET_ARG(T) (va_arg(args, T))
    


    All of the warnings (except improper call within main) that appear during a build can be represented by and verified by the following:
      uint16_t u16 = GET_ARG(uint16_t);
      int16_t n16 = GET_ARG(int16_t);
    


    I don't know what the proper fix is just yet, but perhaps when this is resolved, then perhaps the communication issues will be resolved.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-18 07:53
    Referring to my two previous posts.....

    As I see it, passing uint16_t and int16_t data types to GET_ARG, is the cause of the warnings generated during the build process, whereas uint32_t and int32_t data types do not generate any warnings at all and pass right on through the build process.

    Within sermsg.h, serwrite_uint16(v) and serwrite_int16(v) are defined as follows:
    #define	serwrite_uint16(v)	serwrite_uint32(v)
    #define	serwrite_int16(v)	serwrite_int32(v)
    

    As you can clearly see, these short functions are simply defined by the long functions, and therefore they should be processed exactly the same way, except with different data types sent during the calls.

    At this point, I am assuming that these two defines are actually just garbage, and that the uint16_t and int16_t data types should just be passed to the serwrite_uint32 and serwrite_int32 functions in the first place.

    I do not understand why it was done this way to provide warnings and code collapse. Either way, I am going to toy around with eliminating the serwrite_uint16(v) and serwrite_int16(v) functions and see what happens.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-18 16:39
    I still need to thoroughly test this, but I believe this is the fix for making sersendf.c compatible with the simpletext library. Providing the format string is correct, this code should build without warnings.

    Don't blame me for the code layout... Mine looks neat :)
    /** \file sersendf.c
    	\brief Simplified printf implementation
    */
    #include	"sersendf.h"
    #include	<stdarg.h>
    #include	"simpletext.h"
    #include	"sermsg.h"
    
    /** \brief Simplified printf
    	\param format pointer to output format specifier string stored in FLASH.
    	\param ... output data
    
    	Implements only a tiny subset of printf's format specifiers :-
    
    	%[ls][udcx%]
    
    	l - following data is (32 bits)\n
    	s - following data is short (8 bits)\n
    	none - following data is 16 bits.
    
    	u - unsigned int\n
    	d - signed int\n
    	q - signed int with decimal before the third digit from the right\n
    	c - character\n
    	x - hex\n
    	% - send a literal % character
    
    	Example:
    
    	\code sersendf_P(PSTR("X:%ld Y:%ld temp:%u.%d flags:%sx Q%su/%su%c\n"), target.X, target.Y, current_temp >> 2, (current_temp & 3) * 25, dda.allflags, mb_head, mb_tail, (queue_full()?'F':(queue_empty()?'E':' '))) \endcode
    */
    
    void sersendf_P(PGM_P format, ...)
    {
    	va_list args;
    	va_start(args, format);
    
    	uint16_t i = 0;
    	uint8_t c = 1;
    	uint8_t j = 0;
     
    	while((c = pgm_read_byte(&format[i++])))
    	{
    		if(j)
    		{
    			switch(c)
    			{
    				case 's':
    
    					j = 1;
    
    					break;
    
    				case 'l':
    
    					j = 4;
    
    					break;
    
    				case 'u':
        
    
    					if(j == 4)
    					{
    						serwrite_uint32((uint32_t)va_arg(args, uint32_t));
    					}
    					else
    					{
                   serwrite_uint16((uint16_t)va_arg(args, uint32_t));
    					}
    
    					j = 0;
    
    					break;
    
    				case 'd':
        
                if(j == 4)
    					{
    						serwrite_int32((int32_t)va_arg(args, int32_t));
    					}
    					else
    					{
    						serwrite_int16((int16_t)va_arg(args, int32_t));
    					}
    
    					j = 0;
    
    					break;
    
    				case 'c':
        
                putChar((uint16_t)va_arg(args, uint32_t));
    
    					j = 0;
    
    					break;
    
    				case 'x':
    
    					putStr(PSTR("0x"));
    
    					if(j == 4)
    					{
    						serwrite_hex32((uint32_t)va_arg(args, uint32_t));
    					}
    					else if(j == 1)
    					{
                   serwrite_hex8((uint8_t)va_arg(args, uint32_t));
    					}
    					else
    					{
                   serwrite_hex16((uint16_t)va_arg(args, uint32_t));
    					}
    
    					j = 0;
    
    					break;
    
    				// An original comment
    				//case 'p':
    
    					//serwrite_hex16(GET_ARG(uint16_t));
    
    				case 'q':
    
    					serwrite_int32_vf((int32_t)va_arg(args, int32_t), 3);
    
    					j = 0;
    
    					break;
    
    				default:
    
    					putChar(c);
    
    					j = 0;
    
    					break;
    			}
    		}
    		
    		else
    		{
    			if(c == '%')
    			{
    				j = 2;
    			}
    			else
    			{
    				putChar(c);
    			}
    		}
    	}
    
    	va_end(args);
    }
    
    Source: Teacup Firmware - modified by me
  • idbruceidbruce Posts: 6,197
    edited 2015-02-19 09:39
    Providing the format string is correct, this code should build without warnings.

    I sure was wrong with that statement. The compiler spits out all kinds of warnings, with any kind of formatting, but the code holds up without aborting. As I see it, the compiler really does not like different data types when using stdarg.h, and therefore issues warnings.

    I have reconfigured the test program to show how everything works, utilizing sermsg and sersendf, as well as simpletext. With the exception of the warnings, and unless I am missing something, everything appears to be working well.

    See the attached archive below.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-22 04:34
    A little hindsight 20/20....

    If there is one thing that I have learned during this attempted port, I learned that there are a lot of different issues to consider. If you make one bad choice, then all your work is for nothing, and you must start all over again, or at least that has been true for most of my choices. Luckily for me, it is not that bad, concerning my last bad choice..

    If you have been following along, you will know that I am shooting for an ACCELERATION_RAMPING and a LOOKAHEAD port of the firmware. While both of these choices are good for 3D printing, I don't believe the same holds true for a standard CNC machine. Whereas the ACCELERATION_RAMPING would most likely be beneficial to a standard CNC machine, LOOKAHEAD could be very detrimental, because it joins moves together, to prevent excess oozing of the filament, at the end of a targeted move. In the case of a standard CNC machine, you will not have this oozing problem, and you definitely want to hit the target location. By eliminating all of the conditional compiling for LOOKAHEAD, I have essentially made the movement code useless for a standard CNC machine. However, luckily for me, after doing a little research, I have discovered that the only important files affected are dda.c and dda.h. Considering that I will most likely want to use these files for other projects besides 3D printing, I will now have to edit dda.c and dda.h once again, and leave the LOOKAHEAD conditional compiling in full working order.

    While editing these two files are a bit of a pain, I realize that the situation could have been a lot worse. :)
  • idbruceidbruce Posts: 6,197
    edited 2015-02-23 07:19
    Well folks, I have finally reached the point to where things are starting to get very complicated.

    Porting the files analog.c, heater.c, temp.c, and timer.c, should be a real challenge.

    In addition to getting very complicated, I have stumbled upon a major disappointment with the following code:
    /// How often we overflow and update our clock.
    /// With F_CPU = 16MHz, max is < 4.096ms (TICK_TIME = 65535).
    #define TICK_TIME 2 MS
    
    Source: timer.h


    Although it may appear simple, this setting runs deep to the core of the firmware, or so it appears. This setting will affect all of the previously mentioned files, as well as dda_queue.c and dda.c. It appears to me that TICK_TIME has a maximum value of 65535, and if that is true, for simplicities sake, the fastest that I will be able to run the Propeller is 20MHz, but that is assuming a port that utilizes large portions of existing code and existing variables.

    I definitely want to take full advantage of the Propeller's speed, but for now, I think I will take the easy road (yea right!), and limit the frequency to 20MHz, and later, when I have a much better understanding of it all, I can attempt to alter the code and make it 80MHz compatible.

    EDIT: I just searched all the various configuration files that came with the Teacup firmware, and the highest setting I found for F_CPU was indeed 20MHz, and that was located in config.gen7-v1.1-v1.3.h and config.gen7-v1.4.h
  • idbruceidbruce Posts: 6,197
    edited 2015-02-23 10:15
    You guys sure are being quiet.

    Considering the number of views, I know there is curiousity amongst you. :)

    However I am also curious, as to whether anyone else is digging through the Teacup files.

    It sure would be nice to have a fellow collaborator about this time :)


    As I have said earlier, I know nothing about Arduino, but according to the comments left by the author, timer.c utilizes two different timers, one for general activities, and another for clocking the step times, but they also refer to some type of comparator. Anyhow, I will have to do some more research, but I believe I will be setting up a cog for these two timers and do my counting with CTRA and CTRB. I am not sure how the comparator fits in there yet, but.....

    babysteps
  • idbruceidbruce Posts: 6,197
    edited 2015-02-23 11:23
    With the exception of possibly setting CTRMODE to %11111, I cannot see how CTRA or CTRB will help me. Like I said, this will take some thought and research.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-23 11:50
    AHA
    Now for the bad news OCRn has to be a whole number. If you end up with a decimal number it means that your desired timer will not be exact. The other thing is that your number has to be able to fit into the register. So 255 for an 8bit timers and 65535 for the 16bit timer.
    Source: https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328

    I now believe this is source of my clock speed limitation of 65535:
    /// How often we overflow and update our clock.
    /// With F_CPU = 16MHz, max is < 4.096ms (TICK_TIME = 65535).
    #define TICK_TIME 2 MS
    

    So by rewriting the timer aspect of the code, then perhaps we can achieve

    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000
  • idbruceidbruce Posts: 6,197
    edited 2015-02-25 18:43
    A large portion of the Forger (formerly Teacup) Firmware now compiles for use on the Propeller chip. Here are some of the problems that remain:
      All the files that were deeply embedded with Arduino specific code need to be rewritten and added to the project. Fairly large size project.
      There is some commented Arduino specific code contained within the project files that needs to be reworked for the Propeller. Medium size project.
      Replacing a few minor instances of the Arduino serial interface with the Propeller serial interface. Piece of cake.
      For some odd reason, LOOKAHEAD is not communicating with the DDA. Haven't found it yet.
      Change all 16 bit frequency limitations to 32 bit. Not sure how hard that will be or how deeply it goes.

    All items that need attention will be in comments! The comments will contain a date in the form of //2/25/2015// or //2/25/2015//Bruce//. If you want to look at all the potential problems, just search the documents for Bruce or just a date.

    @Dave Hein - I had to alter the macros a little to get it to compile, but your assistance helped greatly. All references of "IO ## _PIN" were changed to simply "IO".
  • idbruceidbruce Posts: 6,197
    edited 2015-02-25 21:57
    •For some odd reason, LOOKAHEAD is not communicating with the DDA. Haven't found it yet.

    It is not communicating, because it is not compiling. I know this because there is no reference to it in the build status pane, and I also know that it contains errors which should show up in the build status pane. However, I still have not located the problem.

    EDIT: I found it. At the top of dda_lookahead.c, make the following change:

    FROM:
    #ifdef LOOKAHEAD
    
    #include "dda_lookahead.h"
    

    TO:
    #include "dda_lookahead.h"
    
    #ifdef LOOKAHEAD
    

    EDIT: With a few more dated comments, LOOKAHEAD is now communicating with the DDA
  • idbruceidbruce Posts: 6,197
    edited 2015-02-26 07:57
    As you may know, I am not an expert C/C++ programmer, but I am certainly not a beginner either. One thing is for sure, there are certain parts of this firmware that can make your brain go numb, just by looking at the code. For example:
    #undef DEFINE_HEATER
    /// \brief helper macro to fill heater definition struct from config.h
    #define	DEFINE_HEATER(name, pin, pwm) { &(pin ## _WPORT), pin ## _PIN, \
                                            pwm ? (pin ## _PWM) : NULL},
    static const heater_definition_t heaters[NUM_HEATERS] =
    {
    	#include	"config.h"
    };
    #undef DEFINE_HEATER
    

    Alright now, let's convert it to Propeller lingo :)
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-02-26 08:46
    If you look a few lines before the DEFINE_HEATER macro you'll see the declaration of the heater_definition_t struct.
    /// \struct heater_definition_t
    /// \brief simply holds pinout data- port, pin, pwm channel if used
    typedef struct {
        volatile uint8_t *heater_port;    ///< pointer to port. DDR is inferred from this pointer too
        uint8_t  heater_pin;                  ///< heater pin, not masked. eg for PB3 enter '3' here, or PB3_PIN or similar
        volatile uint8_t *heater_pwm;  ///< pointer to 8-bit PWM register, eg OCR0A (8-bit) or ORC3L (low byte, 16-bit)
    } heater_definition_t;
    
    The Prop only has one I/O Port, so the value of heater_port isn't important. Also, since PWM is done in software on the Prop, and there is no PWM register on the Prop, heater_pwm just needs to indicate whether PWM is to be used for this pin. So I would define DEFINE_HEATER on the Prop as
    #define DEFINE_HEATER(name, pin, pwm) { NULL, pin ## _PIN, (uint8_t *)pwm},
    
    Of course, the routines that control the heaters based on the data in this struct need to be modified to do the right thing on the Prop.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-26 09:19
    Dave
    So I would define DEFINE_HEATER on the Prop as

    Code:
    #define DEFINE_HEATER(name, pin, pwm) { NULL, pin ## _PIN, (uint8_t *)pwm},

    You are missing the bigger picture.....

    This is very similar to the previous macros that you helped me with.....

    The whole concept is: User settings are defined in config.h and the various macros throughout Teacup pull in the defines of config.h and set the values where they are needed. By doing it that way, all user settings are located in one header file, so that a person with little or no C/C++ experience, can simply alter the settings in one file to match their machine, and build the project, instead of inserting the values in many different locations, throughout the source code.

    EDIT: In fact, it would be nice to keep the user settings out of the firmware entirely, and perhaps do an sd card read of a configuration file and assign the values to variables at startup.

    EDIT: Or perhaps, at startup, the firmware would look in various locations for the configuration file, like EEPROM (added with something like the file directive in SPIN), the root directory of the SD card, or even the GCODE file itself. And then I suppose the settings could also be configured over a serial connection.

    EDIT: So when the firmware is ready, just burn the EEPROM with the firmware and look for the settings elsewhere.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-02-26 09:47
    Yes, I know about config.h. The sample config.h files use DEFINE_HEATER to add entries to the heaters[] array. I don't understand what you are getting at. You're not going to be able to port the Teacup software just by changing config.h. You are going to have to change other files to accommodate the differences between the AVR and the Prop. You might be able to minimize the changes by trying to emulate the AVR to a certain extent.

    Maybe I misunderstood your comment about converting to "Propeller lingo". I thought you were asking for suggestions on how to handle the DEFINE_HEATER macro.
  • idbruceidbruce Posts: 6,197
    edited 2015-02-26 10:27
    Dave
    Yes, I know about config.h. The sample config.h files use DEFINE_HEATER to add entries to the heaters[] array. I don't understand what you are getting at.

    My point is that I do not want to change the basic theory of operation. Even though I am basically setting this up for my current project, I also want the firmware to be adaptable for other machines, with simple changes to one file. So instead of definining heaters in the heater source, I want to keep them in the config file.
    You are going to have to change other files to accommodate the differences between the AVR and the Prop. You might be able to minimize the changes by trying to emulate the AVR to a certain extent.

    Yes, there are several files that will need severe alterations, but my concept is this..... Maintain as much of the existing source code as possible. When rewriting the necessary files, rewrite the functions and variable names with as many of the existing names as possible. However, in some instances, conversion is a piece of cake, for instance, delay.c and delay.h, have been replaced by #include "simpletools.h", waitcnt(us * value + CNT), and waitcnt(ms * value + CNT), in several locations.

    As I see it, my biggest obstacle is matching or emulating the interrupt procedures, because of my lack of knowledge in this area, but I now have some pretty good documentation on the subject.
    Maybe I misunderstood your comment about converting to "Propeller lingo".

    I certainly could have used different terminology :) Such as, "Alright now, let's port this macro so that I can understand it" :)
Sign In or Register to comment.