Porting from PIC32MX to MZ (PIC32MZ2048EFG100) and am banging head against wall trying to generate a simple RX interrupt on UART3. Please see code below.
void main(void} {
__builtin_disable_interrupts();
//Ensuring all pins config as digital
ANSELA = 0x0000;
ANSELB = 0x0000;
ANSELC = 0x0000;
ANSELD = 0x0000;
ANSELE = 0x0000;
ANSELF = 0x0000;
ANSELG = 0x0000;
//Convenient macrso to do IOUNLOCK
#define PPSUnLock() {SYSKEY=0x0;SYSKEY=0xAA996655;SYSKEY=0x556699AA;CFGCONbits.IOLOCK=0;}
#define PPSLock() {SYSKEY=0x0;SYSKEY=0xAA996655;SYSKEY=0x556699AA;CFGCONbits.IOLOCK=1;}
//Peripheral Pin Select (PPS) Settings for UART3
PPSUnLock();
U3RXRbits.U3RXR = 0b1010;
RPA14Rbits.RPA14R = 0b0001;
PPSLock();
//Config UART3
U3MODEbits.UEN0 = 0; //no flow control
U3MODEbits.UEN1 = 0;
U3MODEbits.LPBACK = 0; // no loopback
U3MODEbits.ABAUD = 0; //no autobaud
U3MODEbits.BRGH = 0;
U3MODEbits.PDSEL0 = 0; //8 data bits, no parity
U3MODEbits.PDSEL1 = 0;
U3MODEbits.STSEL = 0; // 1 stop bit
U3STAbits.URXISEL0 = 0; //RX Interrupt on first byte in FIFO
U3STAbits.URXISEL1 = 0;
U3BRG = CLOSEST_UBRG_VALUE115200; //Macro defined elsewhere, but it works
//Int priorities
IPC39bits.U3EIP = 6;
IPC39bits.U3EIS = 3;
//Int flags
IFS4bits.U3RXIF = 0;
//Int enable/disable
IEC4bits.U3EIE = 0;
IEC4bits.U3TXIE = 0;
IEC4bits.U3RXIE = 1; //Enable int on RX
//Enable multi-vector interrupts
INTCONSET = _INTCON_MVEC_MASK;
__builtin_enable_interrupts();
//Turn on UART3
U3STAbits.URXEN = 1;
U3STAbits.UTXEN = 1;
U3MODEbits.ON = 1;
UART_txEXTCOMandWait('A'); //Function defined elsewhere - I get successful byte "A" sent to my terminal. So TX works.
while(1){Nop();}; //wait in endless loop for interrupt to occur on keystroke
}
Below is my ISR:
void __ISR_AT_VECTOR (_UART3_RX_VECTOR, IPL6SOFT) U3Interrupt(void) {
unsigned int test=0;
Nop(); //Setting a breakpoint here
}
I successfully see an "A" on my terminal screen when running the program, so settings are correct for TX. Typing in text in my terminal screen yields no interrupts. Have verified with scope that signal is making it to the PIC32.
What am I missing here? I'm burning a ton of time on something that should be trivial.
Thanks guys.
Figured it out... It should be:
//Int priorities
IPC39bits.U3EIP = 6;
IPC39bits.U3EIS = 3;
Interesting how this had been working in production on PIC32MX for years.
Related
First off all I am a beginner regarding embedded programming.
For an application I do want to use the MLX90621 thermo pixel array togehter with an STM32G431KB. On the Melexis Website is an example Code with some sort off abstraction. I moddified the lowlevel part of the code to work with the HAL library of the MCU.
For some reason I can read the EEPROM and write to it, get an acknowledge... But when trying to read from the adress 0x60, the RAM, where the sensorvalues are stored i do not get an acknowledge. I do have checkt with an logic analyer and I am sending the correct messages. Just for refference I do have added the code part of the read function.
Has anybody an idea regarding some very dump timing error or something like that.
P.S. Allready tried an different sensor of my order with the exact same result.
int MLX90621_I2CRead(uint8_t slaveAddr,uint8_t command, uint8_t startAddress, uint8_t addressStep, uint8_t nMemAddressRead, uint16_t *data)
{
uint8_t sa = slaveAddr << 1;
int cnt = 0;
int i = 0;
uint8_t cmd[4] = {0,0,0,0};
uint8_t i2cData[132] = {0};
uint16_t *p;
p = data;
cmd[0] = command;
cmd[1] = startAddress;
cmd[2] = addressStep;
cmd[3] = nMemAddressRead;
if (HAL_I2C_Master_Transmit(&hi2c2, sa, cmd, 4, HAL_MAX_DELAY) != HAL_OK)
return -1;
HAL_Delay(1);
//sa = sa | 0x01;
//ack = i2c.read(sa, i2cData, 2*nMemAddressRead, 0);
if (HAL_I2C_Master_Receive(&hi2c2, sa, i2cData, 2*nMemAddressRead, HAL_MAX_DELAY) != HAL_OK)
return -1;
for (cnt = 0; cnt < nMemAddressRead; cnt++) {
i = cnt << 1;
*p++ = (uint16_t)i2cData[i+1]*256 + (uint16_t)i2cData[i];
}
return 0;
}
I am using STM32F1 (STM32F103C8T6) in order to develop a project using FreeRTOS.
The following is my GPIO and USART1 interface configuration:
__GPIOA_CLK_ENABLE();
__USART1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;//115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&huart1);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
The question is: Why does UART transmit work before threads start but not after threads started or from threads? I want to transmit data from threads. i.e
int main(void)
{
Initializations();
//THIS WORKS!!
uart_transmit_buffer[0] = 'H';
uart_transmit_buffer[1] = 'R';
uart_transmit_buffer[2] = '#';
uint8_t nums_in_tr_buf = 0;
nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);
StartAllThreads();
osKernelStart();
for (;;);
}
static void A_Random_Thread(void const *argument)
{
for(;;)
{
if (conditionsMet()) //Executed once when a proper response received.
{
//BUT NOT THIS :(!!
uart_transmit_buffer[0] = 'H';
uart_transmit_buffer[1] = 'R';
uart_transmit_buffer[2] = '#';
uint8_t nums_in_tr_buf = 0;
nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);
}
}
}
I have made sure no thread is in deadlock. The problem is UART_HAL_Transmit gives HAL_BUSY state.
Furthermore, I have dedicated one thread to receiving and parsing information from UART RX and I suspect this might be a cause of the problem. The following is the code:
static void UART_Receive_Thread(void const *argument)
{
uint32_t count;
(void) argument;
int j = 0, word_length = 0;
for (;;)
{
if (uart_line_ready == 0)
{
HAL_UART_Receive(&huart1, uart_receive_buffer, UART_RX_BUFFER_SIZE, 0xFFFF);
if (uart_receive_buffer[0] != 0)
{
if (uart_receive_buffer[0] != END_OF_WORD_CHAR)
{
uart_line_buffer[k] = uart_receive_buffer[0];
uart_receive_buffer[0] = 0;
k++;
}
else
{
uart_receive_buffer[0] = 0;
uart_line_ready = 1;
word_length = k;
k = 0;
}
}
}
if (uart_line_ready == 1)
{
//osThreadSuspend(OLEDThreadHandle);
for (j = 0; j <= word_length; j++)
{
UART_RECEIVED_COMMAND[j] = uart_line_buffer[j];
}
for (j = 0; j <= word_length; j++)
{
uart_line_buffer[j] = 0;
}
uart_line_ready = 0;
RECEIVED_COMMAND = ParseReceivedCommand(UART_RECEIVED_COMMAND);
if (RECEIVED_COMMAND != _ID_)
{
AssignReceivedData (word_length); //Results in uint8_t * RECEIVED_DATA
}
//osThreadResume(OLEDThreadHandle);
}
//Should be no delay in order not to miss any data..
}
}
Another cause to the problem I suspect could be related to interrupts of the system (Also please notice initialization part, I configured NVIC):
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
Any help or guidance to this issue would be highly appreciated. Thanks in advance.
From what I can see HAL_UART_Transmit would've worked with the F4 HAL (v1.4.2) if it weren't for __HAL_LOCK(huart). The RX thread would lock the handle and then the TX thread would try to lock as well and return HAL_BUSY. HAL_UART_Transmit_IT and HAL_UART_Receive_IT don't lock the handle for the duration of the transmit/receive.
Which may cause problems with the State member, as it is non-atomically updated by the helper functions UART_Receive_IT and UART_Transmit_IT. Though I don't think it would affect operation.
You could modify the function to allow simultaneous RX and TX. You'd have to update this every time they release a new version of the HAL.
The problem is that the ST HAL isn't meant to be used with an RTOS. It says so in the definition of the macro __HAL_LOCK. Redefining it to use the RTOS's mutexes might worth trying as well. Same with HAL_Delay() to use the RTOS's thread sleep function.
In general though, sending via a blocking function in a thread should be fine, but I would not receive data using a blocking function in a thread. You are bound to experience overrun errors that way.
Likewise, if you put too much processing in the receive interrupt you might also run into overrun errors. I prefer using DMA for reception, followed by interrupts if I've run out of DMA streams. The interrupt only copies the data to a buffer, similarly to the DMA. A processRxData thread is then used to process the actual data.
When using FreeRTOS, you have to set interrupt priority to 5 or above, because below 5 is reserved for the OS.
So change your code to set the priority to:
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
The problem turned out to be something to do with blocking statements.
Since UART_Receive_Thread has HAL_UART_Receive inside and that is blocking the thread until something is received, that results in a busy HAL (hence, the HAL_BUSY state).
The solution was using non-blocking statements without changing anything else.
i.e. using HAL_UART_Receive_IT and HAL_UART_Transmit_IT at the same time and ignoring blocking statements worked.
Thanks for all suggestions that lead to this solution.
I have an X Drive that is coded in ROBOTC. My team and I have the integrated motor encoders already on the robot (for the autonomous period). However the code for them to run is incorrect. The current autonomous code is below. When I run it, it just goes forward forever and at different speeds.
I have looked at multiple tutorials, but none of them work. Does anyone have the code to make the motors (393 Motors) go at a count of 720?
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1, sensorQuadEncoderOnI2CPort, AutoAssign)
#pragma config(Motor, port2, FL, tmotorVex393_MC29, PIDControl, encoderPort, I2C_1)
#pragma config(Motor, port3, BR, tmotorVex393_MC29, PIDControl, reversed, encoderPort, I2C_1)
#pragma config(Motor, port8, BL, tmotorVex393_MC29, PIDControl, encoderPort, I2C_1)
#pragma config(Motor, port9, FR, tmotorVex393_MC29, PIDControl, reversed, encoderPort, I2C_1)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task main()
{
// Autonomous with Integrated Encoders
nMotorPIDSpeedCtrl[FL] = mtrSpeedReg;
nMotorPIDSpeedCtrl[FR] = mtrSpeedReg;
nMotorPIDSpeedCtrl[BL] = mtrSpeedReg;
nMotorPIDSpeedCtrl[BR] = mtrSpeedReg;
//Clears motor values
nMotorEncoder[FL] = 0;
nMotorEncoder[FR] = 0;
nMotorEncoder[BL] = 0;
nMotorEncoder[BR] = 0;
//Forward
motor[FL] = 63;
motor[FR] = 63;
motor[BL] = 63;
motor[BR] = 63;
while(nMotorEncoder[FL] < 720) {
}
//Clears motor values
nMotorEncoder[FL] = 0;
nMotorEncoder[FR] = 0;
nMotorEncoder[BL] = 0;
nMotorEncoder[BR] = 0;
}
You need to explicitly stop the motors (not just zero out the encoders) after the while loop. Otherwise the robot doesn't know to stop; it just knows that it passed the encoder target.
So this code should work for you:
//Clears motor values
nMotorEncoder[FL] = 0;
nMotorEncoder[FR] = 0;
nMotorEncoder[BL] = 0;
nMotorEncoder[BR] = 0;
motor[FL] = 63;
motor[FR] = 63;
motor[BL] = 63;
motor[BR] = 63;
//Forward
while(nMotorEncoder[FL] < 720) {
}
//stops motors
motor[FL] = 0;
motor[FR] = 0;
motor[BL] = 0;
motor[BR] = 0;
//Clears motor encoder values
nMotorEncoder[FL] = 0;
nMotorEncoder[FR] = 0;
nMotorEncoder[BL] = 0;
nMotorEncoder[BR] = 0;
I'm developing a project with dsPIC33EV256GM002 and I want to use its UART.
So I decided to use PIN18 as RX and PIN17 as TX so I programed PPS as follow:
// UART1 RX1 18 RP41 RPINR18 010 1001 (41)
// UART1 TX1 17 RP40 RPOR3.RP40R 000 0001 (1)
RPINR18bits.U1RXR=41;
RPOR3bits.RP40R = 1;
and I put PIN18 (RB 9) as input setting the bit9 of TRISB.
I used an external 8M XTAL and I set M,N1 and N2 parameter as follow:
// Configure Oscillator to operate the device at 80MHz/40MIPs
// Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
// Fosc= 8M*40/(2*2)=80Mhz for 8M input clock
// To be safe, always load divisors before feedback
CLKDIVbits.PLLPOST = 0; // N1=2
CLKDIVbits.PLLPRE = 0; // N2=2
PLLFBD = 38; // M=(40-2), Fcyc = 40MHz for ECAN baud timer
// Disable Watch Dog Timer
RCONbits.SWDTEN = 0;
I want to configure the TX/RX port as 31250,N,8,1 (standard MIDI parameters)
// configure U1MODE
U1MODEbits.UARTEN = 0; // Bit15 TX, RX DISABLED, ENABLE at end of func
//U1MODEbits.notimplemented; // Bit14
U1MODEbits.USIDL = 0; // Bit13 Continue in Idle
U1MODEbits.IREN = 0; // Bit12 No IR translation
U1MODEbits.RTSMD = 0; // Bit11 Simplex Mode
//U1MODEbits.notimplemented; // Bit10
U1MODEbits.UEN = 0; // Bits8,9 TX,RX enabled, CTS,RTS not
U1MODEbits.WAKE = 0; // Bit7 No Wake up (since we don't sleep here)
U1MODEbits.LPBACK = 0; // Bit6 No Loop Back
U1MODEbits.ABAUD = 0; // Bit5 No Autobaud (would require sending '55')
U1MODEbits.URXINV = 0; // Bit4 IdleState = 1 (for dsPIC)
U1MODEbits.BRGH = 0; // Bit3 16 clocks per bit period
U1MODEbits.PDSEL = 0; // Bits1,2 8bit, No Parity
U1MODEbits.STSEL = 0; // Bit0 One Stop Bit
// U1BRG = (Fcy/(16*BaudRate))-1
// Fcy=40
// U1BRG = (40000000/(16*BaudRate))-1
// U1BRG = (40000000/(16*31250))-1 = 79
U1BRG = 79; // 40Mhz osc, 31250 Baud
// Load all values in for U1STA SFR
U1STAbits.UTXISEL1 = 0; //Bit15 Int when Char is transferred (1/2 config!)
U1STAbits.UTXINV = 0; //Bit14 N/A, IRDA config
U1STAbits.UTXISEL0 = 0; //Bit13 Other half of Bit15
//U1STAbits.notimplemented = 0; //Bit12
U1STAbits.UTXBRK = 0; //Bit11 Disabled
U1STAbits.UTXEN = 0; //Bit10 TX pins controlled by periph
U1STAbits.UTXBF = 0; //Bit9 *Read Only Bit*
U1STAbits.TRMT = 0; //Bit8 *Read Only bit*
U1STAbits.URXISEL = 0; //Bits6,7 Int. on character recieved
U1STAbits.ADDEN = 0; //Bit5 Address Detect Disabled
U1STAbits.RIDLE = 0; //Bit4 *Read Only Bit*
U1STAbits.PERR = 0; //Bit3 *Read Only Bit*
U1STAbits.FERR = 0; //Bit2 *Read Only Bit*
U1STAbits.OERR = 0; //Bit1 *Read Only Bit*
U1STAbits.URXDA = 0; //Bit0 *Read Only Bit*
IPC2bits.U1RXIP = 1; // Mid Range Interrupt Priority level, no urgent reason
IPC3bits.U1TXIP = 1; // Mid Range Interrupt Priority level, no urgent reason
IFS0bits.U1TXIF = 0; // Clear the Transmit Interrupt Flag
IEC0bits.U1TXIE = 1; // Enable Transmit Interrupts
IFS0bits.U1RXIF = 0; // Clear the Recieve Interrupt Flag
IEC0bits.U1RXIE = 1; // Enable Recieve Interrupts
U1MODEbits.UARTEN = 1; // And turn the peripheral on
for your reference this is the OSC configuration
_FOSCSEL(FNOSC_PRIPLL);
_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT);
// Startup directly into XT + PLL
// OSC2 Pin Function: OSC2 is Clock Output
// Primary Oscillator Mode: XT Crystal
_FWDT(FWDTEN_OFF); // Watchdog Timer Enabled/disabled by user software
_FICD(ICS_PGD1); // PGD3 for external PK3/ICD3/RealIce, use PGD2 for PKOB
_FDEVOPT( PWMLOCK_OFF );
_FOSCSEL(FNOSC_PRIPLL);
_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT);
// Startup directly into XT + PLL
// OSC2 Pin Function: OSC2 is Clock Output
// Primary Oscillator Mode: XT Crystal
Since I can't detect data from serial RX because I detect a framing error, I would know if the setting that I used are correct.
Have you similar experience ?
I have got the UART TX working on one pic but cannot get the UART RX working on another PIC. My plan is to have the first PIC send data to the second PIC.
My initialisation code for the first PIC TX is,
Code:
void configure_TX_port(){
/*Port configurations*/
OSCCON = 0X68;
//Push button
TRISC3 = 1;
INLVLC3 = 0;
ANSC3 = 0;
//Led output
TRISC2 = 0;
//TX output
TRISA2 = 0;
ANSA2 = 0;
/*PPS setup for RA2*/
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCK = 0;
RA2PPS = 0x14;
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCK = 1;
/*UART configuration*/
TXEN = 1;
SYNC = 0;
SPEN = 1;
TXSTA = (0x4|0x20);
SPBRG = (int)(4000000L/(16UL * 9600) -1);
}
My send data to the tx code is
Code:
void putch(unsigned char byte) {
/* output one byte */
while (!TXIF) /* set when register is empty */
TXREG = byte;
}
My initialisation code for the second PIC RX is,
void configure_RX_port(){
/*Port configurations*/
OSCCON = 0X68;
//Led output
TRISC3 = 0;
//RX input
TRISC5 = 1;
ANSC5 = 0;
/*UART configuration*/
CREN = 1;
SYNC = 0;
SPEN = 1;
TXSTA = (0x4|0x20);
RCSTA = 0x90;
SPBRG = (int)(4000000L/(16UL * 9600) -1);
}
My receive data code is,
unsigned char getch(void) {
/* retrieve one byte */
unsigned char ret;
while (!RCIF) { /* set when register is not empty */
}
ret = RCREG;
return ret;
}
When I debug the code the getch function gets blocked waiting on a character but my other PIC is sending data. On this PIC RC5 is a designated RX pin so I dont think I have to do any pps configuration.
Rahul
TX1STA = 0b00100100; This enablex TX (TXEN=1) and high baud rate (BRGH = 1)
RC1STA = 0b10000000; This enable the serial port (SPEN = 1)
The only important missing part is your Clock setting and the baudrate you want to have.
I saw 4000000 in the formula, means 4MHz, and /9600, so assume 9600BDS).
Result = 0x25.
SPBRGL = 0x25;
SPBRGH = 0;
This way, your TX should work. Your tx function is good.
Be sure to configure RX and TX pins as DIGITAL by disabling ANSELA, ANSELB and ANSELC.
Your PIC also use PPS, so be sure to configure it the right way.
*********EDITED POST, RECEIVE CONDITION************
The only difference here to get a working receiver is to enable the continuous receiver
bit, CREN.
RC1STA = 0b10010000; //Enable serial port(SPEN) and continuous receive(CREN).
Be sure to set RX pin (RC5 in your case) as an INPUT (TRISC5 = 1) so that it can read any entering data. You should also consider doing an interrupt routine instead of polling the receiver flag bit. That way you're sure not to skip any entering data.
By default at reset all pins on PIC16F1704 are set as analog.
So clear coresponding bits of RX and TX pins in registers ANSELA, ANSELB and ANSELC to set tham as digital.
You look to be using asynchronous mode with SYNC = 0, but do not set TXEN = 1.
Setting CREN = 1 only overrides TXEN in synchronous mode. Try setting TXEN = 1.
I added the following line, TXSTA = (0x4|0x20); to the receiver PIC code and it works now. There is no need for
CREN = 1;
SYNC = 0;
SPEN = 1;
as its setting the same bits.