Je suis un membre de premier cycle d'une équipe de recherche travaillant sur un projet impliquant un ASIC transmettant des RF et son récepteur sans fil qui devrait finalement envoyer des données à un PC.
Le récepteur émet un signal série rapide , continu, asynchrone et non standard (c'est-à-dire pas SPI, I2C, UART, etc.) donc mon travail consiste à écrire un logiciel de microcontrôleur pour interfacer le récepteur à l'ordinateur. Actuellement, mon approche consiste à utiliser des interruptions déclenchées par le front pour placer les données dans un tampon circulaire et effectuer tout le processus de décodage bit par bit dans la boucle principale. Le microcontrôleur doit sortir simultanément ces données via USB (port de communication virtuel) vers l'ordinateur.
Voici un problème que je rencontre et que j'anticipe:
Je ne peux pas traiter les données tamponnées assez rapidement même avec mon processeur ARM Cortex M3 72 MHz assez puissant. Le débit est de 400 Kbps (2,5 us / bit). Pour référence cela ne laisse que 180 cycles par bit (y compris le décodage ET l'ISR, qui a ~ 30 cycles de ouch overhead!). Le MCU doit également gérer de nombreuses autres tâches qu'il interroge dans la boucle principale.
Le pilote du port de communication virtuel USB est également basé sur les interruptions. Cela me rend presque certain que le pilote finira par avoir le processeur interrompu pendant si longtemps qu'il manque la fenêtre de 2,5 microsecondes (180 cycles) dans laquelle un bit peut être transmis. Je ne sais pas comment les conflits d'interruption / races comme celui-ci sont normalement résolus.
La question est donc simplement: que peut-on faire pour résoudre ces problèmes ou n'est-ce pas la bonne approche? Je suis également prêt à envisager des approches moins centrées sur les logiciels. Par exemple, utiliser une puce USB dédiée avec une sorte de machine d'état matérielle pour le décodage, mais ce n'est pas un territoire inconnu.
Réponses:
Autre réponse: arrêtez d'utiliser les interruptions.
Les gens sautent trop facilement pour utiliser les interruptions. Personnellement, je les utilise rarement car ils perdent beaucoup de temps, comme vous le découvrez.
Il est souvent possible d'écrire une boucle principale qui interroge tout si rapidement que sa latence est conforme aux spécifications, et très peu de temps est perdu.
Il peut y avoir certaines choses dans la boucle qui se produisent beaucoup plus souvent que d'autres. Peut-être que les bits entrants par exemple, dans ce cas, ajoutent plus de ces tests, de sorte qu'une plus grande partie du processeur est dédiée à cette tâche.
Il peut y avoir certains événements pour lesquels la latence de cette approche est trop élevée. Par exemple, vous pourriez avoir besoin d'un événement chronométré de façon très précise. Dans ce cas, ayez cet événement sur interruption et ayez tout le reste dans la boucle.
la source
Vous pouvez éventuellement utiliser un FPGA au lieu d'un microcontrôleur pour décoder et mettre en mémoire tampon le flux de données sans fil. Utilisez ensuite le processeur ARM pour vider les tampons FPGA (par exemple en utilisant une interface SPI) et expédiez le contenu via le port USB Comm. C'est du travail, mais un FPGA devrait pouvoir suivre facilement tant que vous êtes en mesure de le réparer assez souvent pour garantir que ses tampons matériels ne dépassent pas (ou si vous pouvez traiter les données perdues à un niveau supérieur du protocole). ).
la source
Facile: utilisez un microcontrôleur PSoC5 .
Vous avez toute la facilité d'utilisation d'un microcontrôleur, en plus il contient un CPLD, vous pouvez donc écrire vos propres périphériques matériels dans Verilog. Écrivez simplement votre décodeur de données série dans verilog et utilisez DMA pour le diffuser sur le port USB.
Pendant ce temps, le puissant cœur ARM 32 bits peut déformer ses instructions Thumb.
la source
Je pense que vous avez un choix d'ingénierie classique à faire: rapide, bon marché, fonctionne: choisissez-en deux.
La solution de @ vicatcu est certainement une bonne solution, mais si vous ne pouvez pas ou ne voulez pas y ajouter plus de matériel (et cela inclut un processeur plus rapide), alors vous devez faire un choix. Si cette liaison série est la plus importante, vous devez vous asseoir dans l'ISR jusqu'à ce que tous les bits aient été collectés. 180 instructions par bit n'est pas mal du tout, mais n'essayez pas de tout faire. Lorsque vous détectez le début d'un transfert, tournez jusqu'à ce que le transfert soit terminé. Remplissez le résultat dans un FIFO, puis reprenez le traitement normal.
Vous ne dites pas combien de temps chaque transmission est mais si elles sont courtes et éclatantes, ce serait une solution viable. Je suis prêt à parier que votre implémentation de port COM virtuel a également un tampon matériel, donc un service d'interruption "retardé" ne devrait pas poser trop de problèmes. En ce qui concerne le reste de ce que le MCU doit faire ... vous avez des décisions de conception à prendre.
la source
Tout d'abord, j'aime déjà certaines réponses ici, et certaines ont obtenu mon vote.
Mais juste pour ajouter une autre solution possible: étant donné les contraintes de votre projet, l'ajout d'un deuxième microcontrôleur serait-il mauvais (cela impliquerait-il une autre exécution de la carte)? Peut-être un simple microcontrôleur 8 bits qui se connecte à votre Cortex-M3 via un périphérique rapide comme SPI. Le contrôleur 8 bits de votre choix interrogerait les bits et formerait les octets comme dans la réponse sélectionnée, mais lorsqu'il a un octet, il pourrait le vider dans le registre de données SPI pour le transfert.
Le côté cortex-M3 interromprait simplement les données SPI reçues. Cela réduit votre précédente interruption déclenchée par les bords externes à 400 KHz à 50 KHz.
Les deux raisons pour lesquelles je suggère cela sont parce que certaines des autres méthodes (PSoC ou FPGA ajouté) sont un peu chères (bien que cela n'ait probablement pas d'importance pour un projet académique à faible volume) et parce qu'elles peuvent vous permettre de préserver certaines la structure de votre code actuel.
En dehors de cela, je pense que l'idée PSoC est géniale avec votre propre périphérique personnalisé transférant via DMA vers USB.
la source
Si votre format de données est similaire à celui d'un UART, mais à un débit en bauds imprévisible mais cohérent, mon inclinaison serait d'utiliser un CPLD pour convertir chaque mot de données entrantes en format SPI ou asynchrone standard. Je ne pense pas qu'il soit nécessaire de pousser jusqu'au bout dans le domaine des CPLD. En fait, même une logique discrète pourrait presque fonctionner. Si vous pouviez générer une horloge qui était un smidgin plus de 5 fois votre débit de données souhaité, vous pourriez utiliser un compteur diviser par cinq et diviser par 16 avec quelques portes. Disposez le compteur de division par cinq de sorte qu'il soit maintenu à zéro chaque fois que l'entrée est inactive et que le compteur de division par 16 est à zéro. Sinon, générez une impulsion d'horloge SPI et heurtez le compteur de division par 16 chaque fois que le compteur de division par cinq atteint 2.
Compte tenu de l'horloge 5x, on pourrait générer l'horloge SPI en utilisant un 16V8 (le dispositif logique programmable le plus petit et le moins cher actuellement disponible). Un deuxième 16V8 ou 22V10 pourrait être utilisé comme diviseur de taux fractionnaire pour générer l'horloge 5x, ou on pourrait utiliser une puce légèrement plus grande (CPLD) et tout faire en un.
Modifier / Addendum
Après un examen plus approfondi, si l'on veut utiliser un CPLD, on peut facilement ajouter quelques améliorations supplémentaires au circuit. Par exemple, on peut assez facilement ajouter une logique pour que le circuit se bloque jusqu'à ce qu'il reçoive au moins 1,5 bit de temps d'arrêt, suivi de 3,5 bits de bit de démarrage; s'il reçoit un bit de démarrage trop court, il devrait recommencer à rechercher le bit d'arrêt. De plus, si l'on utilise SPI, on pourrait utiliser le signal / CS pour s'assurer que le périphérique récepteur verra les données correctement cadrées. Si l'appareil recevant les données SPI peut gérer des trames 10 bits, on pourrait envoyer ces trames directement. Sinon, chaque trame de dix bits pourrait être envoyée en tant que trame de 8 bits avec l'ensemble LSB (7 bits de données), et une trame avec tous les LSB effacés (3 bits de données); l'horloge SPI serait accélérée pendant les bits d'arrêt afin que toutes les données soient envoyées.
Certains microcontrôleurs ont des modules de génération PWM assez polyvalents qui incluent des choses comme la possibilité d'être maintenus en réinitialisation par un signal externe, et de synchroniser leur synchronisation avec la libération d'un tel signal. Si votre microcontrôleur peut le faire, selon ses caractéristiques exactes, cela pourrait considérablement simplifier le circuit CPLD ou de génération de synchronisation.
Une autre approche que Rocketmagnet a quelque peu abordée, serait d'avoir un petit micro dont le seul but est de décoder les données série et de les convertir dans un format utilisable par le micro principal. Votre débit de données de 400 kHz est assez rapide pour le décodage logiciel, mais quelque chose comme un PIC pourrait le gérer s'il n'avait rien d'autre à faire en même temps. Selon les appareils que vous connaissez, cela pourrait être plus facile ou plus difficile que d'utiliser un CPLD.
la source