@ -37,7 +37,7 @@
# include "qstr.h"
# include "obj.h"
# include "runtime.h"
# include "bufhelper .h"
# include "stream .h"
# include "uart.h"
# include "pybioctl.h"
@ -45,41 +45,97 @@
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol. At
/// the physical level it consists of 2 lines: RX and TX.
/// the physical level it consists of 2 lines: RX and TX. The unit of communication
/// is a character (not to be confused with a string character) which can be 8 or 9
/// bits wide.
///
/// See usage model of I2C. UART is very similar. Main difference is
/// parameters to init the UART bus:
/// UART objects can be created and initialised using:
///
/// from pyb import UART
///
/// uart = UART(1, 9600) # init with given baudrate
/// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters
/// uart.init(9600, bits=8, parity=None, stop=1 ) # init with given parameters
///
/// Bits can be 8 or 9, stop can be 1 or 2, parity can be None, 0 (even), 1 (odd) .
/// Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2 .
///
/// Extra method:
/// A UART object acts like a stream object and reading and writing is done
/// using the standard stream methods:
///
/// uart.read(10) # read 10 characters, returns a bytes object
/// uart.readall() # read all available characters
/// uart.readline() # read a line
/// uart.readinto(buf) # read and store into the given buffer
/// uart.write('abc') # write the 3 characters
///
/// Individual characters can be read/written using:
///
/// uart.readchar() # read 1 character and returns it as an integer
/// uart.writechar(42) # write 1 character
///
/// To check if there is anything to be read, use:
///
/// uart.any() # returns True if any characters waiting
# define CHAR_WIDTH_8BIT (0)
# define CHAR_WIDTH_9BIT (1)
struct _pyb_uart_obj_t {
mp_obj_base_t base ;
pyb_uart_t uart_id ;
bool is_enabled ;
UART_HandleTypeDef uart ;
IRQn_Type irqn ;
uint16_t timeout ; // timeout waiting for first char
uint16_t timeout_char ; // timeout waiting between chars
uint16_t char_width ; // 0 for 7,8 bit chars, 1 for 9 bit chars
uint16_t read_buf_len ; // len in chars; buf can hold len-1 chars
volatile uint16_t read_buf_head ; // indexes first empty slot
uint16_t read_buf_tail ; // indexes first full slot (not full if equals head)
byte * read_buf ; // byte or uint16_t, depending on char size
} ;
// this table converts from HAL_StatusTypeDef to POSIX errno
STATIC const byte hal_status_to_errno_table [ 4 ] = {
[ HAL_OK ] = 0 ,
[ HAL_ERROR ] = EIO ,
[ HAL_BUSY ] = EBUSY ,
[ HAL_TIMEOUT ] = ETIMEDOUT ,
} ;
// pointers to all UART objects (if they have been created)
STATIC pyb_uart_obj_t * pyb_uart_obj_all [ 6 ] ;
STATIC mp_obj_t pyb_uart_deinit ( mp_obj_t self_in ) ;
void uart_init0 ( void ) {
for ( int i = 0 ; i < MP_ARRAY_SIZE ( pyb_uart_obj_all ) ; i + + ) {
pyb_uart_obj_all [ i ] = NULL ;
}
}
// unregister all interrupt sources
void uart_deinit ( void ) {
for ( int i = 0 ; i < MP_ARRAY_SIZE ( pyb_uart_obj_all ) ; i + + ) {
pyb_uart_obj_t * uart_obj = pyb_uart_obj_all [ i ] ;
if ( uart_obj ! = NULL ) {
pyb_uart_deinit ( uart_obj ) ;
}
}
}
// assumes Init parameters have been set up correctly
bool uart_init2 ( pyb_uart_obj_t * uart_obj ) {
USART_TypeDef * UARTx = NULL ;
uint32_t GPIO_Pin = 0 ;
uint8_t GPIO_AF_UARTx = 0 ;
USART_TypeDef * UARTx ;
IRQn_Type irqn ;
uint32_t GPIO_Pin ;
uint8_t GPIO_AF_UARTx = 0 ;
GPIO_TypeDef * GPIO_Port = NULL ;
switch ( uart_obj - > uart_id ) {
// USART1 is on PA9/PA10 (CK on PA8), PB6/PB7
case PYB_UART_1 :
UARTx = USART1 ;
irqn = USART1_IRQn ;
GPIO_AF_UARTx = GPIO_AF7_USART1 ;
# if defined (PYBV4) || defined(PYBV10)
@ -96,6 +152,7 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
// USART2 is on PA2/PA3 (CK on PA4), PD5/PD6 (CK on PD7)
case PYB_UART_2 :
UARTx = USART2 ;
irqn = USART2_IRQn ;
GPIO_AF_UARTx = GPIO_AF7_USART2 ;
GPIO_Port = GPIOA ;
@ -107,6 +164,7 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
// USART3 is on PB10/PB11 (CK on PB12), PC10/PC11 (CK on PC12), PD8/PD9 (CK on PD10)
case PYB_UART_3 :
UARTx = USART3 ;
irqn = USART3_IRQn ;
GPIO_AF_UARTx = GPIO_AF7_USART3 ;
# if defined(PYBV3) || defined(PYBV4) | defined(PYBV10)
@ -122,6 +180,7 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
// UART4 is on PA0/PA1, PC10/PC11
case PYB_UART_4 :
UARTx = UART4 ;
irqn = UART4_IRQn ;
GPIO_AF_UARTx = GPIO_AF8_UART4 ;
GPIO_Port = GPIOA ;
@ -133,6 +192,7 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
// USART6 is on PC6/PC7 (CK on PC8)
case PYB_UART_6 :
UARTx = USART6 ;
irqn = USART6_IRQn ;
GPIO_AF_UARTx = GPIO_AF8_USART6 ;
GPIO_Port = GPIOC ;
@ -145,6 +205,9 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
return false ;
}
uart_obj - > irqn = irqn ;
uart_obj - > uart . Instance = UARTx ;
// init GPIO
GPIO_InitTypeDef GPIO_InitStructure ;
GPIO_InitStructure . Pin = GPIO_Pin ;
@ -155,7 +218,6 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
HAL_GPIO_Init ( GPIO_Port , & GPIO_InitStructure ) ;
// init UARTx
uart_obj - > uart . Instance = UARTx ;
HAL_UART_Init ( & uart_obj - > uart ) ;
uart_obj - > is_enabled = true ;
@ -163,6 +225,7 @@ bool uart_init2(pyb_uart_obj_t *uart_obj) {
return true ;
}
/* obsolete and unused
bool uart_init ( pyb_uart_obj_t * uart_obj , uint32_t baudrate ) {
UART_HandleTypeDef * uh = & uart_obj - > uart ;
memset ( uh , 0 , sizeof ( * uh ) ) ;
@ -175,53 +238,54 @@ bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) {
uh - > Init . OverSampling = UART_OVERSAMPLING_16 ;
return uart_init2 ( uart_obj ) ;
}
*/
void uart_deinit ( pyb_uart_obj_t * uart_obj ) {
uart_obj - > is_enabled = false ;
UART_HandleTypeDef * uart = & uart_obj - > uart ;
HAL_UART_DeInit ( uart ) ;
if ( uart - > Instance = = USART1 ) {
__USART1_FORCE_RESET ( ) ;
__USART1_RELEASE_RESET ( ) ;
__USART1_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART2 ) {
__USART2_FORCE_RESET ( ) ;
__USART2_RELEASE_RESET ( ) ;
__USART2_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART3 ) {
__USART3_FORCE_RESET ( ) ;
__USART3_RELEASE_RESET ( ) ;
__USART3_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = UART4 ) {
__UART4_FORCE_RESET ( ) ;
__UART4_RELEASE_RESET ( ) ;
__UART4_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART6 ) {
__USART6_FORCE_RESET ( ) ;
__USART6_RELEASE_RESET ( ) ;
__USART6_CLK_DISABLE ( ) ;
}
bool uart_rx_any ( pyb_uart_obj_t * self ) {
return self - > read_buf_tail ! = self - > read_buf_head
| | __HAL_UART_GET_FLAG ( & self - > uart , UART_FLAG_RXNE ) ! = RESET ;
}
bool uart_rx_any ( pyb_uart_obj_t * uart_obj ) {
return __HAL_UART_GET_FLAG ( & uart_obj - > uart , UART_FLAG_RXNE ) ;
// Waits at most timeout milliseconds for at least 1 char to become ready for
// reading (from buf or for direct reading).
// Returns true if something available, false if not.
STATIC bool uart_rx_wait ( pyb_uart_obj_t * self , uint32_t timeout ) {
uint32_t start = HAL_GetTick ( ) ;
for ( ; ; ) {
if ( self - > read_buf_tail ! = self - > read_buf_head | | __HAL_UART_GET_FLAG ( & self - > uart , UART_FLAG_RXNE ) ! = RESET ) {
return true ; // have at least 1 char ready for reading
}
if ( HAL_GetTick ( ) - start > = timeout ) {
return false ; // timeout
}
__WFI ( ) ;
}
}
int uart_rx_char ( pyb_uart_obj_t * uart_obj ) {
uint8_t ch ;
if ( HAL_UART_Receive ( & uart_obj - > uart , & ch , 1 , 0 ) ! = HAL_OK ) {
ch = 0 ;
// assumes there is a character available
int uart_rx_char ( pyb_uart_obj_t * self ) {
if ( self - > read_buf_tail ! = self - > read_buf_head ) {
// buffering via IRQ
int data ;
if ( self - > char_width = = CHAR_WIDTH_9BIT ) {
data = ( ( uint16_t * ) self - > read_buf ) [ self - > read_buf_tail ] ;
} else {
data = self - > read_buf [ self - > read_buf_tail ] ;
}
self - > read_buf_tail = ( self - > read_buf_tail + 1 ) % self - > read_buf_len ;
return data ;
} else {
// no buffering
return self - > uart . Instance - > DR ;
}
return ch ;
}
void uart_tx_char ( pyb_uart_obj_t * uart_obj , int c ) {
STATIC void uart_tx_char ( pyb_uart_obj_t * uart_obj , int c ) {
uint8_t ch = c ;
HAL_UART_Transmit ( & uart_obj - > uart , & ch , 1 , 100000 ) ;
HAL_UART_Transmit ( & uart_obj - > uart , & ch , 1 , uart_obj - > timeout ) ;
}
void uart_tx_strn ( pyb_uart_obj_t * uart_obj , const char * str , uint len ) {
HAL_UART_Transmit ( & uart_obj - > uart , ( uint8_t * ) str , len , 100000 ) ;
HAL_UART_Transmit ( & uart_obj - > uart , ( uint8_t * ) str , len , uart_obj - > timeout ) ;
}
void uart_tx_strn_cooked ( pyb_uart_obj_t * uart_obj , const char * str , uint len ) {
@ -233,6 +297,36 @@ void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
}
}
// this IRQ handler is set up to handle RXNE interrupts only
void uart_irq_handler ( mp_uint_t uart_id ) {
// get the uart object
pyb_uart_obj_t * self = pyb_uart_obj_all [ uart_id - 1 ] ;
if ( self = = NULL ) {
// UART object has not been set, so we can't do anything, not
// even disable the IRQ. This should never happen.
return ;
}
if ( __HAL_UART_GET_FLAG ( & self - > uart , UART_FLAG_RXNE ) ! = RESET ) {
int data = self - > uart . Instance - > DR ; // clears UART_FLAG_RXNE
if ( self - > read_buf_len ! = 0 ) {
uint16_t next_head = ( self - > read_buf_head + 1 ) % self - > read_buf_len ;
if ( next_head ! = self - > read_buf_tail ) {
// only store data if room in buf
if ( self - > char_width = = CHAR_WIDTH_9BIT ) {
( ( uint16_t * ) self - > read_buf ) [ self - > read_buf_head ] = data ;
} else {
self - > read_buf [ self - > read_buf_head ] = data ;
}
self - > read_buf_head = next_head ;
}
} else {
// TODO set flag for buffer overflow
}
}
}
/******************************************************************************/
/* Micro Python bindings */
@ -241,61 +335,96 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void
if ( ! self - > is_enabled ) {
print ( env , " UART(%u) " , self - > uart_id ) ;
} else {
print ( env , " UART(%u, baudrate=%u, bits=%u, sto p=%u " ,
print ( env , " UART(%u, baudrate=%u, bits=%u, parity = " ,
self - > uart_id , self - > uart . Init . BaudRate ,
self - > uart . Init . WordLength = = UART_WORDLENGTH_8B ? 8 : 9 ,
self - > uart . Init . StopBits = = UART_STOPBITS_1 ? 1 : 2 ) ;
self - > uart . Init . WordLength = = UART_WORDLENGTH_8B ? 8 : 9 ) ;
if ( self - > uart . Init . Parity = = UART_PARITY_NONE ) {
print ( env , " , parity= None) " ) ;
print ( env , " None " ) ;
} else {
print ( env , " , parity= %u) " , self - > uart . Init . Parity = = UART_PARITY_EVEN ? 0 : 1 ) ;
print ( env , " %u " , self - > uart . Init . Parity = = UART_PARITY_EVEN ? 0 : 1 ) ;
}
print ( env , " , stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u) " ,
self - > uart . Init . StopBits = = UART_STOPBITS_1 ? 1 : 2 ,
self - > timeout , self - > timeout_char , self - > read_buf_len ) ;
}
}
/// \method init(baudrate, *, bits=8, stop=1, parity=None )
/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64 )
///
/// Initialise the UART bus with the given parameters:
///
/// - `baudrate` is the clock rate.
/// - `bits` is the number of bits per byte, 8 or 9.
/// - `stop` is the number of stop bits, 1 or 2.
/// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
STATIC const mp_arg_t pyb_uart_init_args [ ] = {
{ MP_QSTR_baudrate , MP_ARG_REQUIRED | MP_ARG_INT , { . u_int = 9600 } } ,
{ MP_QSTR_bits , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 8 } } ,
{ MP_QSTR_stop , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 1 } } ,
{ MP_QSTR_parity , MP_ARG_KW_ONLY | MP_ARG_OBJ , { . u_obj = mp_const_none } } ,
} ;
# define PYB_UART_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_init_args)
/// - `stop` is the number of stop bits, 1 or 2.
/// - `timeout` is the timeout in milliseconds to wait for the first character.
/// - `timeout_char` is the timeout in milliseconds to wait between characters.
/// - `read_buf_len` is the character length of the read buffer (0 to disable).
STATIC mp_obj_t pyb_uart_init_helper ( pyb_uart_obj_t * self , mp_uint_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
static const mp_arg_t allowed_args [ ] = {
{ MP_QSTR_baudrate , MP_ARG_REQUIRED | MP_ARG_INT , { . u_int = 9600 } } ,
{ MP_QSTR_bits , MP_ARG_INT , { . u_int = 8 } } ,
{ MP_QSTR_parity , MP_ARG_OBJ , { . u_obj = mp_const_none } } ,
{ MP_QSTR_stop , MP_ARG_INT , { . u_int = 1 } } ,
{ MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 1000 } } ,
{ MP_QSTR_timeout_char , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 0 } } ,
{ MP_QSTR_read_buf_len , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 64 } } ,
} ;
STATIC mp_obj_t pyb_uart_init_helper ( pyb_uart_obj_t * self , mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
// parse args
mp_arg_val_t vals [ PYB_UART_INIT_NUM_ARGS ] ;
mp_arg_parse_all ( n_args , args , kw_args , PYB_UART_INIT_NUM_ARGS , pyb_uart_init_args , vals ) ;
mp_arg_val_t args [ MP_ARRAY_SIZE ( allowed_args ) ] ;
mp_arg_parse_all ( n_args , pos_ args, kw_args , MP_ARRAY_SIZE ( allowed_args ) , allowed_args , arg s) ;
// set the UART configuration values
memset ( & self - > uart , 0 , sizeof ( self - > uart ) ) ;
UART_InitTypeDef * init = & self - > uart . Init ;
init - > BaudRate = vals [ 0 ] . u_int ;
init - > WordLength = vals [ 1 ] . u_int = = 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B ;
switch ( vals [ 2 ] . u_int ) {
case 1 : init - > StopBits = UART_STOPBITS_1 ; break ;
default : init - > StopBits = UART_STOPBITS_2 ; break ;
}
if ( vals [ 3 ] . u_obj = = mp_const_none ) {
init - > BaudRate = args [ 0 ] . u_int ;
init - > WordLength = args [ 1 ] . u_int = = 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B ;
if ( args [ 2 ] . u_obj = = mp_const_none ) {
init - > Parity = UART_PARITY_NONE ;
} else {
mp_int_t parity = mp_obj_get_int ( vals [ 3 ] . u_obj ) ;
mp_int_t parity = mp_obj_get_int ( args [ 2 ] . u_obj ) ;
init - > Parity = ( parity & 1 ) ? UART_PARITY_ODD : UART_PARITY_EVEN ;
}
switch ( args [ 3 ] . u_int ) {
case 1 : init - > StopBits = UART_STOPBITS_1 ; break ;
default : init - > StopBits = UART_STOPBITS_2 ; break ;
}
init - > Mode = UART_MODE_TX_RX ;
init - > HwFlowCtl = UART_HWCONTROL_NONE ;
init - > OverSampling = UART_OVERSAMPLING_16 ;
// init UART (if it fails, it's because the port doesn't exist)
if ( ! uart_init2 ( self ) ) {
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_ValueError , " UART port %d does not exist " , self - > uart_id ) ) ;
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_ValueError , " UART(%d) does not exist " , self - > uart_id ) ) ;
}
// set timeouts
self - > timeout = args [ 4 ] . u_int ;
self - > timeout_char = args [ 5 ] . u_int ;
// setup the read buffer
m_del ( byte , self - > read_buf , self - > read_buf_len < < self - > char_width ) ;
if ( init - > WordLength = = UART_WORDLENGTH_9B & & init - > Parity = = UART_PARITY_NONE ) {
self - > char_width = CHAR_WIDTH_9BIT ;
} else {
self - > char_width = CHAR_WIDTH_8BIT ;
}
self - > read_buf_head = 0 ;
self - > read_buf_tail = 0 ;
if ( args [ 6 ] . u_int < = 0 ) {
// no read buffer
self - > read_buf_len = 0 ;
self - > read_buf = NULL ;
HAL_NVIC_DisableIRQ ( self - > irqn ) ;
__HAL_UART_DISABLE_IT ( & self - > uart , UART_IT_RXNE ) ;
} else {
// read buffer using interrupts
self - > read_buf_len = args [ 6 ] . u_int ;
self - > read_buf = m_new ( byte , args [ 6 ] . u_int < < self - > char_width ) ;
__HAL_UART_ENABLE_IT ( & self - > uart , UART_IT_RXNE ) ;
HAL_NVIC_SetPriority ( self - > irqn , 0xd , 0xd ) ; // next-to-next-to lowest priority
HAL_NVIC_EnableIRQ ( self - > irqn ) ;
}
return mp_const_none ;
@ -320,41 +449,51 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
// check arguments
mp_arg_check_num ( n_args , n_kw , 1 , MP_OBJ_FUN_ARGS_MAX , true ) ;
// create object
pyb_uart_obj_t * o = m_new_obj ( pyb_uart_obj_t ) ;
o - > base . type = & pyb_uart_type ;
o - > is_enabled = false ;
// work out port
o - > uart_id = 0 ;
int uart_id = 0 ;
if ( MP_OBJ_IS_STR ( args [ 0 ] ) ) {
const char * port = mp_obj_str_get_str ( args [ 0 ] ) ;
if ( 0 ) {
# if defined(PYBV10)
} else if ( strcmp ( port , " XA " ) = = 0 ) {
o - > uart_id = PYB_UART_XA ;
uart_id = PYB_UART_XA ;
} else if ( strcmp ( port , " XB " ) = = 0 ) {
o - > uart_id = PYB_UART_XB ;
uart_id = PYB_UART_XB ;
} else if ( strcmp ( port , " YA " ) = = 0 ) {
o - > uart_id = PYB_UART_YA ;
uart_id = PYB_UART_YA ;
} else if ( strcmp ( port , " YB " ) = = 0 ) {
o - > uart_id = PYB_UART_YB ;
uart_id = PYB_UART_YB ;
# endif
} else {
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_ValueError , " UART port %s does not exist " , port ) ) ;
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_ValueError , " UART(%s) does not exist " , port ) ) ;
}
} else {
o - > uart_id = mp_obj_get_int ( args [ 0 ] ) ;
uart_id = mp_obj_get_int ( args [ 0 ] ) ;
if ( uart_id < 1 | | uart_id > MP_ARRAY_SIZE ( pyb_uart_obj_all ) ) {
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_ValueError , " UART(%d) does not exist " , uart_id ) ) ;
}
}
pyb_uart_obj_t * self ;
if ( pyb_uart_obj_all [ uart_id - 1 ] = = NULL ) {
// create new UART object
self = m_new0 ( pyb_uart_obj_t , 1 ) ;
self - > base . type = & pyb_uart_type ;
self - > uart_id = uart_id ;
pyb_uart_obj_all [ uart_id - 1 ] = self ;
} else {
// reference existing UART object
self = pyb_uart_obj_all [ uart_id - 1 ] ;
}
if ( n_args > 1 | | n_kw > 0 ) {
// start the peripheral
mp_map_t kw_args ;
mp_map_init_fixed_table ( & kw_args , n_kw , args + n_args ) ;
pyb_uart_init_helper ( o , n_args - 1 , args + 1 , & kw_args ) ;
pyb_uart_init_helper ( self , n_args - 1 , args + 1 , & kw_args ) ;
}
return o ;
return self ;
}
STATIC mp_obj_t pyb_uart_init ( mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
@ -366,7 +505,35 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
/// Turn off the UART bus.
STATIC mp_obj_t pyb_uart_deinit ( mp_obj_t self_in ) {
pyb_uart_obj_t * self = self_in ;
uart_deinit ( self ) ;
self - > is_enabled = false ;
UART_HandleTypeDef * uart = & self - > uart ;
HAL_UART_DeInit ( uart ) ;
if ( uart - > Instance = = USART1 ) {
HAL_NVIC_DisableIRQ ( USART1_IRQn ) ;
__USART1_FORCE_RESET ( ) ;
__USART1_RELEASE_RESET ( ) ;
__USART1_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART2 ) {
HAL_NVIC_DisableIRQ ( USART2_IRQn ) ;
__USART2_FORCE_RESET ( ) ;
__USART2_RELEASE_RESET ( ) ;
__USART2_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART3 ) {
HAL_NVIC_DisableIRQ ( USART3_IRQn ) ;
__USART3_FORCE_RESET ( ) ;
__USART3_RELEASE_RESET ( ) ;
__USART3_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = UART4 ) {
HAL_NVIC_DisableIRQ ( UART4_IRQn ) ;
__UART4_FORCE_RESET ( ) ;
__UART4_RELEASE_RESET ( ) ;
__UART4_CLK_DISABLE ( ) ;
} else if ( uart - > Instance = = USART6 ) {
HAL_NVIC_DisableIRQ ( USART6_IRQn ) ;
__USART6_FORCE_RESET ( ) ;
__USART6_RELEASE_RESET ( ) ;
__USART6_CLK_DISABLE ( ) ;
}
return mp_const_none ;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( pyb_uart_deinit_obj , pyb_uart_deinit ) ;
@ -383,103 +550,175 @@ STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( pyb_uart_any_obj , pyb_uart_any ) ;
/// \method send(send, *, timeout=5000)
/// Send data on the bus:
///
/// - `send` is the data to send (an integer to send, or a buffer object).
/// - `timeout` is the timeout in milliseconds to wait for the send.
///
/// \method writechar(char)
/// Write a single character on the bus. `char` is an integer to write.
/// Return value: `None`.
STATIC const mp_arg_t pyb_uart_send_args [ ] = {
{ MP_QSTR_send , MP_ARG_REQUIRED | MP_ARG_OBJ , { . u_obj = MP_OBJ_NULL } } ,
{ MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 5000 } } ,
} ;
# define PYB_UART_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_send_args)
STATIC mp_obj_t pyb_uart_send ( mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
// TODO assumes transmission size is 8-bits wide
pyb_uart_obj_t * self = args [ 0 ] ;
// parse args
mp_arg_val_t vals [ PYB_UART_SEND_NUM_ARGS ] ;
mp_arg_parse_all ( n_args - 1 , args + 1 , kw_args , PYB_UART_SEND_NUM_ARGS , pyb_uart_send_args , vals ) ;
STATIC mp_obj_t pyb_uart_writechar ( mp_obj_t self_in , mp_obj_t char_in ) {
pyb_uart_obj_t * self = self_in ;
// get the buffer to send from
mp_buffer_info_t bufinfo ;
uint8_t data [ 1 ] ;
pyb_buf_get_for_send ( vals [ 0 ] . u_obj , & bufinfo , data ) ;
// get the character to write (might be 9 bits)
uint16_t data = mp_obj_get_int ( char_in ) ;
// send the data
HAL_StatusTypeDef status = HAL_UART_Transmit ( & self - > uart , bufinfo . buf , bufinfo . len , vals [ 1 ] . u_in t) ;
// write the data
HAL_StatusTypeDef status = HAL_UART_Transmit ( & self - > uart , ( uint8_t * ) & data , 1 , self - > timeout ) ;
if ( status ! = HAL_OK ) {
// TODO really need a HardwareError object, or something
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_Exception , " HAL_UART_Transmit failed with code %d " , status ) ) ;
nlr_raise ( mp_obj_new_exception_arg1 ( & mp_type_OSError , ( mp_obj_t ) ( mp_uint_t ) hal_status_to_errno_table [ status ] ) ) ;
}
return mp_const_none ;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW ( pyb_uart_send_obj , 1 , pyb_uart_send ) ;
STATIC MP_DEFINE_CONST_FUN_OBJ_2 ( pyb_uart_writechar_obj , pyb_uart_writechar ) ;
/// \method recv(recv, *, timeout=5000)
/// \method readchar()
/// Receive a single character on the bus.
/// Return value: The character read, as an integer. Returns -1 on timeout.
STATIC mp_obj_t pyb_uart_readchar ( mp_obj_t self_in ) {
pyb_uart_obj_t * self = self_in ;
if ( uart_rx_wait ( self , self - > timeout ) ) {
return MP_OBJ_NEW_SMALL_INT ( uart_rx_char ( self ) ) ;
} else {
// return -1 on timeout
return MP_OBJ_NEW_SMALL_INT ( - 1 ) ;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( pyb_uart_readchar_obj , pyb_uart_readchar ) ;
/// \method readinto(buf, len=-1)
///
/// Receive data on the bus:
/// Read data on the bus:
///
/// - `recv` can be an integer, which is the number of bytes to receive,
/// or a mutable buffer, which will be filled with received bytes.
/// - `timeout` is the timeout in milliseconds to wait for the receive.
/// - `buf` is a mutable buffer which will be filled with read characters.
/// - `len` is the maximum number of characters to read; if negative, uses len(buf).
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
/// otherwise the same buffer that was passed in to `recv`.
STATIC const mp_arg_t pyb_uart_recv_args [ ] = {
{ MP_QSTR_recv , MP_ARG_REQUIRED | MP_ARG_OBJ , { . u_obj = MP_OBJ_NULL } } ,
{ MP_QSTR_timeout , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = 5000 } } ,
} ;
# define PYB_UART_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_recv_args)
STATIC mp_obj_t pyb_uart_recv ( mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
// TODO assumes transmission size is 8-bits wide
/// Return value: number of characters stored in buf.
STATIC mp_obj_t pyb_uart_readinto ( mp_uint_t n_args , const mp_obj_t * pos_args ) {
pyb_uart_obj_t * self = pos_args [ 0 ] ;
pyb_uart_obj_t * self = args [ 0 ] ;
// parse args
mp_arg_val_t vals [ PYB_UART_RECV_NUM_ARGS ] ;
mp_arg_parse_all ( n_args - 1 , args + 1 , kw_args , PYB_UART_RECV_NUM_ARGS , pyb_uart_recv_args , vals ) ;
// get the buffer to receive into
// get the buffer to read into
mp_buffer_info_t bufinfo ;
mp_obj_t o_ret = pyb_buf_get_for_recv ( vals [ 0 ] . u_obj , & bufinfo ) ;
// receive the data
HAL_StatusTypeDef status = HAL_UART_Receive ( & self - > uart , bufinfo . buf , bufinfo . len , vals [ 1 ] . u_int ) ;
mp_get_buffer_raise ( pos_args [ 1 ] , & bufinfo , MP_BUFFER_WRITE ) ;
bufinfo . len > > = self - > char_width ;
// adjust the length, if given
if ( n_args = = 3 ) {
mp_int_t len = mp_obj_get_int ( pos_args [ 2 ] ) ;
if ( len > = 0 & & len < bufinfo . len ) {
bufinfo . len = len ;
}
}
if ( status ! = HAL_OK ) {
// TODO really need a HardwareError object, or something
nlr_raise ( mp_obj_new_exception_msg_varg ( & mp_type_Exception , " HAL_UART_Receive failed with code %d " , status ) ) ;
// make sure we want at least 1 char, and wait for it to become available
if ( bufinfo . len = = 0 | | ! uart_rx_wait ( self , self - > timeout ) ) {
return MP_OBJ_NEW_SMALL_INT ( 0 ) ;
}
// return the received data
if ( o_ret = = MP_OBJ_NULL ) {
return vals [ 0 ] . u_obj ;
} else {
return mp_obj_str_builder_end ( o_ret ) ;
// read the chars
byte * buf = bufinfo . buf ;
for ( ; ; ) {
int data = uart_rx_char ( self ) ;
if ( self - > char_width = = CHAR_WIDTH_9BIT ) {
* ( uint16_t * ) buf = data ;
buf + = 2 ;
} else {
* buf + + = data ;
}
if ( - - bufinfo . len = = 0 | | ! uart_rx_wait ( self , self - > timeout_char ) ) {
// return the number of chars read
return mp_obj_new_int ( ( buf - ( byte * ) bufinfo . buf ) > > self - > char_width ) ;
}
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW ( pyb_uart_recv_obj , 1 , pyb_uart_recv ) ;
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR ( pyb_uart_readinto_obj , 2 , pyb_uart_readinto ) ;
STATIC const mp_map_elem_t pyb_uart_locals_dict_table [ ] = {
// instance methods
{ MP_OBJ_NEW_QSTR ( MP_QSTR_init ) , ( mp_obj_t ) & pyb_uart_init_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_deinit ) , ( mp_obj_t ) & pyb_uart_deinit_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_any ) , ( mp_obj_t ) & pyb_uart_any_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_send ) , ( mp_obj_t ) & pyb_uart_send_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_recv ) , ( mp_obj_t ) & pyb_uart_recv_obj } ,
/// \method read([nbytes])
{ MP_OBJ_NEW_QSTR ( MP_QSTR_read ) , ( mp_obj_t ) & mp_stream_read_obj } ,
/// \method readall()
{ MP_OBJ_NEW_QSTR ( MP_QSTR_readall ) , ( mp_obj_t ) & mp_stream_readall_obj } ,
/// \method readline()
{ MP_OBJ_NEW_QSTR ( MP_QSTR_readline ) , ( mp_obj_t ) & mp_stream_unbuffered_readline_obj } ,
/// \method write(buf)
{ MP_OBJ_NEW_QSTR ( MP_QSTR_write ) , ( mp_obj_t ) & mp_stream_write_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_writechar ) , ( mp_obj_t ) & pyb_uart_writechar_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_readchar ) , ( mp_obj_t ) & pyb_uart_readchar_obj } ,
{ MP_OBJ_NEW_QSTR ( MP_QSTR_readinto ) , ( mp_obj_t ) & pyb_uart_readinto_obj } ,
} ;
STATIC MP_DEFINE_CONST_DICT ( pyb_uart_locals_dict , pyb_uart_locals_dict_table ) ;
mp_uint_t uart_ioctl ( mp_obj_t self_in , mp_uint_t request , int * errcode , . . . ) {
STATIC mp_uint_t pyb_uart_read ( mp_obj_t self_in , void * buf_in , mp_uint_t size , int * errcode ) {
pyb_uart_obj_t * self = self_in ;
byte * buf = buf_in ;
// check that size is a multiple of character width
if ( size & self - > char_width ) {
* errcode = EIO ;
return MP_STREAM_ERROR ;
}
// convert byte size to char size
size > > = self - > char_width ;
// make sure we want at least 1 char
if ( size = = 0 ) {
return 0 ;
}
// wait for first char to become available
if ( ! uart_rx_wait ( self , self - > timeout ) ) {
// we can either return 0 to indicate EOF (then read() method returns b'')
// or return EAGAIN error to indicate non-blocking (then read() method returns None)
return 0 ;
}
// read the data
byte * orig_buf = buf ;
for ( ; ; ) {
int data = uart_rx_char ( self ) ;
if ( self - > char_width = = CHAR_WIDTH_9BIT ) {
* ( uint16_t * ) buf = data ;
buf + = 2 ;
} else {
* buf + + = data ;
}
if ( - - size = = 0 | | ! uart_rx_wait ( self , self - > timeout_char ) ) {
// return number of bytes read
return buf - orig_buf ;
}
}
}
STATIC mp_uint_t pyb_uart_write ( mp_obj_t self_in , const void * buf_in , mp_uint_t size , int * errcode ) {
pyb_uart_obj_t * self = self_in ;
const byte * buf = buf_in ;
// check that size is a multiple of character width
if ( size & self - > char_width ) {
* errcode = EIO ;
return MP_STREAM_ERROR ;
}
// write the data
HAL_StatusTypeDef status = HAL_UART_Transmit ( & self - > uart , ( uint8_t * ) buf , size > > self - > char_width , self - > timeout ) ;
if ( status = = HAL_OK ) {
// return number of bytes written
return size ;
} else {
* errcode = hal_status_to_errno_table [ status ] ;
return MP_STREAM_ERROR ;
}
}
STATIC mp_uint_t pyb_uart_ioctl ( mp_obj_t self_in , mp_uint_t request , int * errcode , . . . ) {
pyb_uart_obj_t * self = self_in ;
va_list vargs ;
va_start ( vargs , errcode ) ;
@ -502,9 +741,9 @@ mp_uint_t uart_ioctl(mp_obj_t self_in, mp_uint_t request, int *errcode, ...) {
}
STATIC const mp_stream_p_t uart_stream_p = {
//.read = uart_read, // TODO
//.write = uart_write, // TODO
. ioctl = uart_ioctl ,
. read = pyb_uart_read ,
. write = pyb_uart_write ,
. ioctl = pyb_ uart_ioctl,
. is_text = false ,
} ;
@ -513,6 +752,8 @@ const mp_obj_type_t pyb_uart_type = {
. name = MP_QSTR_UART ,
. print = pyb_uart_print ,
. make_new = pyb_uart_make_new ,
. getiter = mp_identity ,
. iternext = mp_stream_unbuffered_iter ,
. stream_p = & uart_stream_p ,
. locals_dict = ( mp_obj_t ) & pyb_uart_locals_dict ,
} ;