2015-04-02 04:34 PM
I am trying to create a smartcard driver on the STM32F103. I am using USART3, and the ST8024CTR interface chip.
My problem is that I can read the cards (with a hack of a workaround), but cannot write to them. What is happening is that I am using an interrupt driven read/write state machine, but the receive interrupts are happening way too soon. When I need to send a command to the card, I build an APDU structure, set my state variable to send the CLA, and enable the TXE interrupt. This immediately fires, and the state machine sends the CLA and sets the state to send the INS. The TXE interrupt triggers again (almost immediately since CLA went straight to the shift register) and I send the INS and set the state variable to send the P1. The TXE interrupt triggers again and I send P1 then set the state variable to send P2. The TXE interrupt triggers again and I send P1. If I need to write data, then I set the state variable to send the length expected byte. Else I skip this and part in () below.(The TXE interrupt triggers again and I send length expected.)Then I disable the transmitter and enable the RXNE interrupt to wait for the procedure byte.Here's where things go wrong. The RXNE interrupt fires almost immediately, but when I read the data byte, it contains the value of P2. If I sent the length expected byte, it will fire again and I'll get the length expected byte. Either way the next thing I get is the procedure byte. I can work around this by ignoring anything that isn't a valid procedure byte (INS or -INS, 0x60, 0x6* or 0x9*), and that allows me to read data from my cards (since none of the commands INS bytes look like a procedure byte).When I need to write data to the card, after getting the procedure byte, I disable the receiver and re-enable the TXE interrupt with my state set to send my data. Then the TXE interrupt fires, and I send a byte of data. If there is no more data to send, then I disable the TXE interrupt, enable the RXNE interrupt, and wait for the SW1 SW2 status word. Here again, the RXNE interrupt fires when I don't expect it. I get the last byte or two of the data I wrote read back in. Why is the USART receiving the data it wrote? Is the smartcard mode not smart enough to reject the data it just sent? Is it possible I missed some setting that would prevent this behavior? Or is this something that is known and has to be worked around some way, perhaps by leaving the RXNE enabled always, and keeping track of what I just sent and discarding the received data if it matches?Any insights would be appreciated. #smartcard2015-04-03 02:00 AM
H Jeff,
I suggest you reviewhttp://www.st.com/web/en/catalog/tools/FM147/CL1794/SC961/SS1743/LN1734/PF257847
(if not yet done).There is a firmware that aims to provide resources that facilitate the development of an application using the USART peripheral in Smartcard mode.You can start by checking examples & comparing them with your code.Then if you still have same issue, let us know.-Mayla-To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2015-04-03 10:19 AM
Yes, I have gone over that code in the past, and no offense, but I find it terrible. For one, it is completely foreground driven, which is very inefficient. Two, the whole SC_Handler routine is very confusing, and doesn't have very good error handling.
However, from looking at it, it looks as if this code also suffers from this issue. Looking atSC_SendData, there is this portion of the code:/* Send body length to/from SC ---------------------------------------------*/
if(SC_ADPU->Body.LC)
{
SCData = SC_ADPU->Body.LC;
USART_SendData(SC_USART, SCData);
while(USART_GetFlagStatus(SC_USART, USART_FLAG_TC) == RESET)
{
}
}
else if(SC_ADPU->Body.LE)
{
SCData = SC_ADPU->Body.LE;
USART_SendData(SC_USART, SCData);
while(USART_GetFlagStatus(SC_USART, USART_FLAG_TC) == RESET)
{
}
}
/* Flush the SC_USART DR */
(void)USART_ReceiveData(SC_USART);
/* --------------------------------------------------------
Wait Procedure byte from card:
1 - ACK
2 - NULL
3 - SW1; SW2
-------------------------------------------------------- */
if((USART_ByteReceive(&locData, SC_RECEIVE_TIMEOUT)) == SUCCESS)
In this code, every byte sent has a wait for that byte to complete (something that would be insane to do in an interrupt handler), and following that, there is the ''Flush the SC_USART DR'' bit before looking for the procedure byte. This implies that this code too has to deal with the echo of every byte sent as well, but by waiting on each byte, then only the last one is still in the receive buffer when they call the ''flush'' to get rid of it.
I've got my code working by incrementing a counter for each byte I send, leaving the RXNE enabled for the entire exchange, and decrementing the counter and ignoring the received data if it is non-zero in the receive routine. So if I send 5 bytes, the counter will go up, and after receiving 5 bytes will go back to zero, so I know that the next byte I receive will actually come from the card, and not be an echo of what I sent. This works, but at the cost of nearly twice as many interrupts as needed.
I do however believe it is a flaw in the design that the data sent is received back. I can't imagine anyone who would actually want it to work that way. I've used the smartcard mode on other processors, such as the H8/300 series, and they certainly don't have this issue. But it is what it is, and I've worked around it.