This blog documents focuses on the UART approach for the electronic load that peteroakes, jc2048 and Jan Cumps designed. UART combined with SCPI are the programming interface for the instruments. |
UART
Info: initial design used UART1 as 2nd option. When switching to the Red MSP432 LaunchPad, this switched to UART6.
Where you see UART1, think UART6.
UART module if USB UART0
9600/8/1/N
UART module if TTL UART6
115200/8/1/N
The project uses uses the TI-RTOS UART driver.
Buffered output for transmit
Interrupt driven for receive, wake up RTOS task (with semaphore) whenever a character arrives on the Rx line.
void *threadUART(void *arg0) { char input; UART_Params uartParams; int iError; /* Call driver init functions */ // GPIO_init(); UART_init(); /* Configure the LED pin */ GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); /* Create a UART with data processing off. */ UART_Params_init(&uartParams); uartParams.writeDataMode = UART_DATA_BINARY; uartParams.readDataMode = UART_DATA_BINARY; uartParams.readReturnMode = UART_RETURN_FULL; uartParams.readEcho = UART_ECHO_OFF; // uartParams.baudRate = 9600; uartParams.readMode = UART_MODE_CALLBACK; // the uart uses a read interrupt // uartParams.readCallback = &UART00_IRQHandler; // function called when the uart interrupt fires #ifdef SCPI_UART_0 uartParams.baudRate = 9600; uartParams.readCallback = &UART00_IRQHandler; // function called when the uart interrupt fires uart = UART_open(Board_UART0, &uartParams); #else #ifdef SCPI_UART_6 uartParams.baudRate = 115200; uartParams.readCallback = &UART00_IRQHandler; // function called when the uart interrupt fires uart = UART_open(Board_UART6, &uartParams); #else #error "define a valid UART" #endif #endif if (uart == NULL) { /* UART_open() failed */ while (1); }
The interrupt is very simple. It posts a semaphore to flag our UART task that we have a character on the receive line.
void UART00_IRQHandler(UART_Handle handle, void *buffer, size_t num) { sem_post(&SEM_uart_rx); }
There are 2 touchpoints with the SCPI interpreter. UART module knows about SCPI lib. SCPI is UART-unaware.
- initialises the SCPI lib (is that smart? *) with scpi_instrument_init() edit: moved to main().
- each character received directly sent to SCPI lib with scpi_instrument_input().
while (1) { UART_read(uart, &input, 1); iError = sem_wait(&SEM_uart_rx); // when a character is received via UART, the interrupt handler will release the binary semaphore while (iError) { // POSIX reported error with semaphore. Can't recover. } // in my case: I get an interrupt for a single character, no need to loop. GPIO_toggle(Board_GPIO_LED1); // LED B - visual clue that we've received a request over USB scpi_instrument_input((const char *)&input, 1); GPIO_toggle(Board_GPIO_LED1); // LED B - visual clue off }
- SCPI lib uses SCPI_Write() to send info to UART (although the SCPI lib isn't aware of that. The linker resolves this dependency. The only thing that the SCPI lib requires is that "there is a function named SCPI_Write()" somewhere).
size_t SCPI_Write(scpi_t * context, const char * data, size_t len) { (void) context; GPIO_toggle(Board_GPIO_LED1); // LED B - visual clue that we send a reply over USB UART_write(uart, data, len); GPIO_toggle(Board_GPIO_LED1); // LED B - visual clue offB return len; }
compile option to choose the UART:
SCPI_UART_0
SCPI_UART_6
Undefining SCPI_UART_6 and defining SCPI_UART_0 enables UART0 (USB debug port)
Undefining SCPI_UART_0 and defining SCPI_UART_6 enables UART6 (TTL 3V3)
It allows to select the port without code changes.
#ifdef SCPI_UART_0 uart = UART_open(Board_UART0, &uartParams); #else #ifdef SCPI_UART_1 uart = UART_open(Board_UART1, &uartParams); #else #error "define a valid UART" #endif #endif