I2C auf Intel XScale PXA255



  • Hi

    danke für die Kommentare. Also, Infos über Registers usw. ist vorhanden (die dev-manual vom Intel PXA), sie ist aber schon recht umfangreich und geht wenig auf "wie man letztendlich den I2C Controller verwendet" sondern "was für Register gibt es, wo sie gemappt werden, usw" und wenn du noch nie mit dem I2C Bus bzw. Protokoll zu tun hattest, kannst du nicht viel damit anfangen, außer rumprobieren (wofür ich eigentlich keine Zeit hat). Denn ich möchte ein kleines Framework dafür schreiben, so dass man beliege I2C Sensoren anschließen kann ohne am Treiber Framework rumzubasteln (den gasamtem Funktionsumfang von I2C muss ich jedoch nicht unterstützen).



  • supertux schrieb:

    In der Doku steht, dass der I2C Controller in 4 Modi arbeiten kann (Master-Transmit, Master-Receive, usw). Was ich noch nicht verstehe: werden die Modi vom Treiber gewechselt oder macht der Controller das von alleine?

    das müsste in der doku stehen. normalerweise sorgt so'n iic-peripheral nur das grundlegende framing, also start/stop-conditions setzen, bits raus- und reinschieben usw, damit man sich mit möglichst vielen iic-slaves unterhalten kann. alles andere muss der treiber machen.

    supertux schrieb:

    Was wäre effizienter/besser, polling oder interrupts?

    interrupts sind meistens besser, weil du ja 'nen taskswitching-kernel einsetzt und weil iic ein ziemlich langsamer bus ist.

    supertux schrieb:

    ich will an sich nur Sensoren anschließen und diese auslesen/ansteuern, heißt es also, dass der Controler als Master arbeiten soll?

    ja, dein controller ist immer der, der die taktimpulse erzeugt.

    ach ja, und vergiss nicht die pull-ups. iic ist 'open drain'. die teilnehmer ziehen den bus nur runter. pull-ups sorgen für den high-pegel.

    supertux schrieb:

    und wenn du noch nie mit dem I2C Bus bzw. Protokoll zu tun hattest, kannst du nicht viel damit anfangen, außer rumprobieren

    http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
    🙂



  • erstaml danke für due Antwort

    ~fricky schrieb:

    supertux schrieb:

    Was wäre effizienter/besser, polling oder interrupts?

    interrupts sind meistens besser, weil du ja 'nen taskswitching-kernel einsetzt und weil iic ein ziemlich langsamer bus ist.

    so dachte ich es mir auch, aber in meinen Echtezeitmikrokernel möchte ich so wenig wie möglich im Kernel Modus wechseln (möchte Anzahl Context-Switches so gering wie möglich halten) und weiß nicht, wie viele Interrupts der I2C abgeben könnte. Ich werde das mal experimentell bestimmen.



  • supertux schrieb:

    so dachte ich es mir auch, aber in meinen Echtezeitmikrokernel möchte ich so wenig wie möglich im Kernel Modus wechseln (möchte Anzahl Context-Switches so gering wie möglich halten)

    naja, ein hardware-interrupt ist ja kein richtiger context-switch. darum muss sich dein scheduler nicht kümmern, das regelt die CPU alles selber. aber ich weiss ja nicht, wie dein system aufgebaut ist.

    supertux schrieb:

    und weiß nicht, wie viele Interrupts der I2C abgeben könnte. Ich werde das mal experimentell bestimmen.

    oft passiert das bei jedem empfangenen byte und wenn das senderegister leer ist. wenn dein controller intern für iic FIFOs hat, dann natürlich seltener (z.b. wenn der empfangs-FIFO halb voll ist bzw. nach einem timeout und wenn der sende-FIFO leer ist). dazu kommen noch interrupts wie 'arbitration lost', für slave-modi noch ein paar mehr. aber die kannste sicherlich alle ausmaskieren. abhängig von FIFO-grösse, taktfrequenz, etc. kann man ausrechnen, wie viele interrupts pro sekunde bei vollast maximal auftreten können. du musst nun mal das user-manual des controllers durchackern. da kommst du nicht drum herum.
    🙂



  • ~fricky schrieb:

    supertux schrieb:

    so dachte ich es mir auch, aber in meinen Echtezeitmikrokernel möchte ich so wenig wie möglich im Kernel Modus wechseln (möchte Anzahl Context-Switches so gering wie möglich halten)

    naja, ein hardware-interrupt ist ja kein richtiger context-switch. darum muss sich dein scheduler nicht kümmern, das regelt die CPU alles selber. aber ich weiss ja nicht, wie dein system aufgebaut ist.

    Der Scheduler nicht, aber die Kontexte der ausführende Tasks muss dennoch gespeichert werden. Der Zeitgeber (für periodeische Releases von Tasks) wird mit dem OSTIMER + Match Register realisiert. Ein Match wird nur durch Interrupt bekannt gemacht, deswegen muss ich bei IRQs den gesamten Context der Tasks sepeichern (ein Context-Swicth im Prinzip, auch wenn die ausführende Tasks nicht preemted wird). 99% aller behandelten IRQs sind für Tasks Releases (was wegen EDF Scheduler zur Preemtion führen kann) 😉 aus diesem Grund möchte ich keine weitere "unnötige" IRQ Behandlungen machen.



  • wieso stört eine zusätzliche interruptquelle? der scheduler hat doch seinen eigenen timer interrupt, oder nicht? auf einem ARM-system, das nur 'nen primitiven interrupt-controller hat (einer, der nicht vektorisiert), hast du zwar für alle IRQs eine globale ISR (ebenso für FIQs), aber dann kannstes doch so machen:

    __interrupt void global_isr(void)
    {
       int src = ....; // Interruptquelle ausfindig machen
    
       switch (src)
       {
          case RTOS_TIMER:
          Schedule();       // <-- RTOS tick
          break;
    
          case IIC:
          HandleIIC();      // <--- das IIC peripheral will was von uns
          break;
    
          case ...;         // noch mehr interruptquellen
          ....
    
          default:
          HandleSpuriousInterrupt();   // <--- sollte nicht auftreten
          break;      
       }
    }
    

    ^^aber falls ich dich falsch verstanden habe, betrachte das posting bitte als hinfällig
    🙂



  • ~fricky schrieb:

    der scheduler hat doch seinen eigenen timer interrupt,

    ja, aber damit hat es nicht zu tun: mein IRQ handler sieht so aus:

    __arm_core_irq_handler:
    sub         lr, lr, #4 
    stmfd       sp!, {r0-r12, lr}
    mov         r0, sp 
    bl          cpu_save_context
    
    bl          arm_core_irq_handler
    
    mov         r0, sp 
    bl          cpu_restore_context
    ldmfd       sp!, {r0-r12, pc}^
    

    und cpu_save_context und cpu_restore_context sind für Context Switches zuständig. Da 99% aller IRQ Scheduler Entscheidungen sind, war es deswgen am einfachsten dort den Kontext zu speichern.



  • ^^na, das lässt sich ja leicht abändern, so dass andere interrupts, ausser scheduler-interrupts, keine save- und restore-contexts bewirken.
    🙂



  • ~fricky schrieb:

    ^^na, das lässt sich ja leicht abändern, so dass andere interrupts, ausser scheduler-interrupts, keine save- und restore-contexts bewirken.
    🙂

    theoretisch schon, aber das möchte ich jetzt nicht, wie sagt man so schön "never touch a running system"? Ist mir zu heiß und hab Angst mich zu verbrennen 😉



  • supertux schrieb:

    ~fricky schrieb:

    ^^na, das lässt sich ja leicht abändern, so dass andere interrupts, ausser scheduler-interrupts, keine save- und restore-contexts bewirken.
    🙂

    theoretisch schon, aber das möchte ich jetzt nicht, wie sagt man so schön "never touch a running system"?

    auch wenn's offensichtlich eine unschönheit enthält? mich würde es jedenfalls stören, wenn diese context-switch funktionen, bei jedem interrupt, egal wer ihn auslöste, aufgerufen werden. naja, aber du wirst schon wissen, was du tust.
    🙂


Anmelden zum Antworten