diff --git a/comm/doc/images/rx_dma_driven.png b/comm/doc/images/rx_dma_driven.png new file mode 100644 index 0000000000000000000000000000000000000000..35718ae1098e1f60b9cc103de56c3aae0df0ade8 Binary files /dev/null and b/comm/doc/images/rx_dma_driven.png differ diff --git a/comm/doc/images/rx_irq_driven.png b/comm/doc/images/rx_irq_driven.png new file mode 100644 index 0000000000000000000000000000000000000000..680e0dc3cf58220fcb1a65b9aba506cc63551e5b Binary files /dev/null and b/comm/doc/images/rx_irq_driven.png differ diff --git a/comm/doc/images/tx_dma_driven.png b/comm/doc/images/tx_dma_driven.png new file mode 100644 index 0000000000000000000000000000000000000000..67c123e66b435f417588f3bbead77ee846b3a9c2 Binary files /dev/null and b/comm/doc/images/tx_dma_driven.png differ diff --git a/comm/doc/images/tx_irq_driven.png b/comm/doc/images/tx_irq_driven.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec39eba1a6f7759fe03eb6da992311ac1b94829 Binary files /dev/null and b/comm/doc/images/tx_irq_driven.png differ diff --git a/comm/include/comm.h b/comm/include/comm.h index 64b70fed8ddfb8bcb398d1726a0bf37a1393d1a5..c6ca16db0f5509e672ac3199c464dd8969b28533 100644 --- a/comm/include/comm.h +++ b/comm/include/comm.h @@ -18,8 +18,68 @@ typedef enum {COMM_SUCCESS=0x00,/*!< The communication module has ended successf } comm_error; /** - * \brief + * \brief Generic communication device structure * + * This structure implements a generic interface to a communication device in three + * different modes: blocking, interrupt driven and DMA driven. + * + * It is intended to be the intermediate structure between a user application + * that requires access to a communication device, and the actual communication + * device. + * + * On the communication device side, a set of functions must be implemented and + * assigned to this structure at initialization time. Furthermore, the module + * implementing this functions should implement the following features: + * * Configure the hardware to operate as desired. + * * Configure the interrupts and their priorities. + * * Configure the DMA transactions (in case they are enabled). + * * Implement the functions required by this structure to initiate and cancel + * RX and TX transactions using both IRQ and DMA. + * * Implement the basic IRQ and DMa handler functions. + * + * On the user application side, another set of functions must be also implemented + * and assigned to this structure at initialization time. The user application + * should be in charge of initializing this structure and any other data structure + * required. + * + * In blocking mode, the IRQ driven transactions are used except when the use of + * DMA is enbaled, in which case the DMA driven transactions are used. + * + * The following diagram descrives the transmission operation when using + * interrupts, and how the user application, the communication module and the + * actual communication device work together: + * + *  + * + * The user application starts a TX driven transmission by calling the comm_send_irq() + * function, which in turn calls the low level communication function pointed by + * the parameter send_irq. At this point the interrupt handler is called each time + * a byte is actually sent, which calls the comm_do_irq_send() function to update + * the internal state and, in turn, calls the user callback function pointed by + * irq_send_cb. + * + * While the data transfer is in progress the user can call the comm_is_send_done() + * function to check the status of the transmission and the comm_get_error() + * function to check for errors (if any). This functions can be used with any kind + * of non-blobking transactions (IRQ and DMA). + * + * The following diagram descrives the reception operation when using + * interrupts, and how the user application, the communication module and the + * actual communication device work together: + * + *  + * + * The reception is only enabled when the user application calls the comm_receive_irq() + * function, all data received before this function is called will be lost. This + * function calls the low level communication function pointed by the parameter + * receive_irq. + * + * At this point the interrupt handler is called each time a byte is received, which + * calls the comm_do_irq_receive() function to update the internal state and, in + * turn, calls the user callback function pointed by irq_receive_cb. The reception + * remains active until the desired number of bytes are received, or the user + * application cancels it. + * */ typedef struct { @@ -92,8 +152,11 @@ typedef struct */ unsigned char use_dma; /** - * \brief + * \brief DMA termination flag * + * This parameter is used in the comm_do_irq_send() function to indicate whether + * the interrupt is generated by the last transmitted byte of a DMA transaction + * or not. */ unsigned char dma_waiting_buffer_empty; /** @@ -104,173 +167,342 @@ typedef struct */ unsigned char error; /** - * \brief + * \brief Time structure to handle timeouts * + * This parameter is used to handle reception timeouts to avoid that the reception + * functions get blocked due to missing bytes or communication errors. */ TTime *time; /** - * \brief + * \brief pointer to a user data structure * + * This parameter is used to store a user data structure which is passed as a + * parameter to the user callback functions (irq_send_cb(),irq_receive_cb(), + * dma_send_cb() and dma_receive_cb()). */ void *data; /* IRQ functions */ + /** + * \defgroup harware_irq_pointers Hardware IRQ related function pointeris + * + * This set of functions, that must be implemented by the low level hardware + * communication module (either USART, I2C, SPI or any other communication + * device), are intended to handle interrupt driven receptions and transmissions. + * + * This function pointers must be assigned by the initialization function + * of the communication module. + * + */ + /**@{*/ /** - * \brief + * \brief Pointer to a function to start a transmission using interrupts * + * This function should send the first byte through the communication device, + * clear any pending interrupt transmission complete flag and enable this + * interrupt in order to send the remaining of the data. */ unsigned char (*send_irq)(unsigned char first_byte); /** - * \brief + * \brief Pointer to a function to enable the transmission interrupts * + * This function should clear any pending transmission complete interrupt and + * enable this interrupt, but without sending any data through the communication + * device. */ unsigned char (*enable_tx_irq)(void); /** - * \brief + * \brief Pointer to a function to start a reception using interrupts * + * This function should only enable the reception interrupts so that the IRQ + * handler function is called each time a new data byte is received. */ unsigned char (*receive_irq)(void); /** - * \brief + * \brief Pointer to a function to cancel a current reception using interrupts * + * This function should only disable the reception interrupts so that the IRQ + * handler function is no longer called. */ unsigned char (*cancel_receive_irq)(void); + /**@}*/ /* DMA functions */ + /** + * \defgroup harware_dma_pointers Hardware DMA related function pointers + * + * This set of functions, that must be implemented by the low level hardware + * communication module (either USART, I2C, SPI or any other communication + * device), are intended to handle DMA driven receptions and transmissions. + * + * This function pointers must be assigned by the initialization function + * of the communication module. + * + */ + /**@{*/ /** - * \brief + * \brief Pointer to a function to start a transmission using DMA * + * This function should configure and enable the corresponding DMA channel + * to transfer the desired ammount of data from the internal buffer to the + * communication device. TX DMA interrupts should be enabled so that the + * corresponding IRQ handler is called when the transaction is complete or + * when an error ocurrs. */ unsigned char (*send_dma)(unsigned char *data,unsigned short int length); /** - * \brief + * \brief Pointer to a function to start a reception using DMA * + * This function should configure and enable the corresponding DMA channel + * to transfer the desired ammount of data from the communication device to + * the internal buffer. RX DMA interrupts should be enabled so that the + * corresponding IRQ handler is called when the transaction is complete or + * when an error ocurrs. */ unsigned char (*receive_dma)(unsigned char *data,unsigned short int length); /** - * \brief + * \brief Pointer to a function to cancel a current reception using DMA * + * This function should abort the current RX DMA transaction in case there + * is any active. */ unsigned char (*cancel_receive_dma)(void); + /**@}*/ /* irq callbacks */ + /** + * \defgroup callback_irq_pointers User IRQ related function pointers + * + * This set of functions, that must be implemented by the user module that + * uses the coomunication structure, are intended to handle the specific + * requirements of each application using interrupt driven communications. + * + * This function pointers must be assigned by the initialization function + * of the user module. + * + */ + /**@{*/ /** - * \brief + * \brief Callback function to handle the end of interrupt driven transmissions * + * This function is called whenever an IRQ driven transmission is completed so + * that the user application can perform any required action. + * + * Depending on the return value of this function, the comm_do_irq_send() + * function will send the next byte on the internal buffer (0x01) or the byte + * returned by this function (0x00). */ unsigned char (*irq_send_cb)(void *data,unsigned char *byte); /** - * \brief + * \brief Callback function to handle the end of interrupt driven receptions * + * This function is called whenever an IRQ driven reception is completed so that + * the user application can perform any required action. */ unsigned char (*irq_receive_cb)(void *data,unsigned char byte); + /**@}*/ /* dma callbacks */ + /** + * \defgroup callback_dma_pointers User DMA related function pointers + * + * This set of functions, that must be implemented by the user module that + * uses the coomunication structure, are intended to handle the specific + * requirements of each application using DMA driven communications. + * + * This function pointers must be assigned by the initialization function + * of the user module. + */ + /**@{*/ /** - * \brief + * \brief Callback functions to handle the end of DMA driven transmissions * + * This function is called whenever an DMA driven transmission is completed so + * that the user application can perform any required action. */ unsigned char (*dma_send_cb)(void *data); /** - * \brief + * \brief Callback functions to handle the end of DMA driven receptions * + * This function is called whenever an DMA driven reception is completed so that + * the user application can perform any required action. */ unsigned char (*dma_receive_cb)(void *data); + /**@}*/ }TComm; /* public functions */ /** - * \brief + * \brief Function to initialize the communications structure + * + * This function initializes a TComm structure by default. All function + * pointer are set to dummy functions that do nothing. These functions + * have to be assigned to valid functions afterwards. * + * This functions allows to enable or disable the use of the DMA. This + * option can not be modified afterwards. The TTime structure, if provided, + * will allow the comunicatin device to use timeouts during reception. + * Otherwise, the timeout feature will be disabled. + * + * \param dev pointer to a valid TComm structure to be initialized. If + * memory is not pre-allocated before calling this function, its + * behavior is unpredictable. + * \param use_dma flag to enable (0x01) or disable (0x00) the use of + * the DMA for the communcations structure. Any other value is + * interpreted as an enable. + * \param time a pointer to an initiliazed TTime structure to enable the + * use of timeouts. If timeouts are not desired or required, this + * parameter must be set to NULL (0x00000000). */ void comm_init(TComm *dev,unsigned char use_dma,TTime *time); /** - * \brief + * \brief Function to start a blocking transmission + * + * This function is used to start a transmission in blocking mode. By default + * the interrupt driven transmission is used, unless the use of the DMA has been + * enabled in the call to the comm_init() function, in which case the DMA driven + * transmission is used. + * + * This function blocks until all bytes have been transmitted or there has been + * an error. * + * \param dev pointer to a valid TComm structure to be initialized. If + * memory is not pre-allocated before calling this function, its + * behavior is unpredictable. + * \param data pointer to a vector where the data to be transmitted is stored. + * Memory for this parameter must be pre-allocated before calling this + * function to avoid unexpected behaviour. + * \param length Number of bytes to be transmitted. + * + * \return the status of the transmission. The possible values are the elements + * in the comm_error ennumeraiton. */ comm_error comm_send(TComm *dev,unsigned char *data,unsigned short int length); /** - * \brief + * \brief Function to start a blocking reception with a timeout * + * This function is used to start a reception in blocking mode. By default + * the interrupt driven reception is used, unless the use of the DMA has been + * enabled in the call to the comm_init() function, in which case the DMA driven + * reception is used. + * + * This function blocks until all bytes have been received, there has been an + * error or the ammount of time specified as timeout has elapsed. + * + * \param dev pointer to a valid TComm structure to be initialized. If + * memory is not pre-allocated before calling this function, its + * behavior is unpredictable. + * \param data pointer to a vector where the received data is to be stored. + * Memory for this parameter must be pre-allocated before calling this + * function to avoid unexpected behaviour. + * \param length Number of bytes to be received. + * \param timeout maximum time in micro-seconds to wait for the desired ammount + * of bytes. If the TTime structure is not valid this parameter is ignored. + * + * \return the status of the transmission. The possible values are the elements + * in the comm_error ennumeraiton. */ comm_error comm_receive(TComm *dev,unsigned char *data,unsigned short int *length,unsigned long int timeout); /* IRQ functions */ /** - * \brief + * \brief Function to start an interrupt driven transmission + * + * This function is used to start a reception in IRQ driven mode. This function + * starts sending the data but returns immediatelly, reporting an error, if any. + * The data in the input parameter is copied to the internal buffer before it + * returns. + * + * This function calls the function of the low level communication module pointed + * by the send_irq parameter. * + * \param dev pointer to a valid TComm structure to be initialized. If + * memory is not pre-allocated before calling this function, its + * behavior is unpredictable. + * \param data pointer to a vector where the data to be transmitted is stored. + * Memory for this parameter must be pre-allocated before calling this + * function to avoid unexpected behaviour. + * \param length Number of bytes to be transmitted. + * + * \return the status of the transmission. The possible values are the elements + * in the comm_error ennumeraiton. */ comm_error comm_send_irq(TComm *dev,unsigned char *data,unsigned short int length); /** - * \brief + * \brief Function to handle the end of the transmission of a single byte * + * This function should be called from the interrupt handler each time a byte has + * been sent. If this function is called as a result of the last byte of a DMA + * transfer being sent, it calls the corresponding DMA transmission callback + * function. + * + * If this function is called as a result of a byte beign sent in an IRQ driven + * transfer, this function calls the corresponding IRQ transmission callback + * function. When the last byte has been sent, this function automatically stops + * the current transmission, and returns a value of 0x00 to report it. */ unsigned char comm_do_irq_send(TComm *dev,unsigned char *byte); /** - * \brief + * \brief Function to start an interrupt driven reception * */ comm_error comm_receive_irq(TComm *dev,unsigned short int length); /** - * \brief + * \brief Function to handle the reception of a single byte * */ unsigned char comm_do_irq_receive(TComm *dev,unsigned char byte); /** - * \brief + * \brief Function to get the received data * */ comm_error comm_get_received_data(TComm *dev,unsigned char *data,unsigned short int *length); /** - * \brief + * \brief Function to cancel the current interrupt driven reception * */ void comm_cancel_irq_receive(TComm *dev); /* DMA functions */ /** - * \brief + * \brief Function to start a DMA driven transmission * */ comm_error comm_send_dma(TComm *dev,unsigned char *data,unsigned short int length); /** - * \brief + * \brief Function to handle the transmission of all bytes * */ void comm_do_dma_send(TComm *dev); /** - * \brief + * \brief Function to start a DMA driven reception * */ comm_error comm_receive_dma(TComm *dev,unsigned char *data,unsigned short int length); /** - * \brief + * \brief Function to handle the reception of all desired bytes * */ void comm_do_dma_receive(TComm *dev); /** - * \brief + * \brief Function to cancel the current DMA driven reception * */ void comm_cancel_dma_receive(TComm *dev); /* common functions */ /** - * \brief + * \brief Function to check whether the current transmission has ended or not * */ comm_error comm_is_send_done(TComm *dev); /** - * \brief + * \brief Function to check whether the current reception has ended or not * */ comm_error comm_is_receive_done(TComm *dev); /** - * \brief + * \brief Function to get the communication error * */ inline unsigned char comm_get_error(TComm *dev); /** - * \brief + * \brief Function to set the communication error * */ inline void comm_set_error(TComm *dev, unsigned char error); -/** - * \brief - * - */ #endif