Hallo allerseits, ich lese mich gerade in das Thema Embedded Linux ein. Jetzt frage ich mich, wie Echtzeitanforderungen gelöst werden und gelöst werden können. Es gibt ja explizites Echtzeit-Linux wie RTAI, Xenomai oder den RT-Preempt-Patch. So wie ich das verstehe, können diese Umsetzungen beliebigen Tasks Echtzeitfähigkeit verschaffen, also im Grunde "normalen" Linuxprogrammen. Ist es auch möglich auf einem Prozessor mit Linux ohne Echtzeiteigenschaften nebenher interruptgesteuert "Echtzeitcode" auszuführen? In dem Falle wäre das ja quasi ein reines Embedded-Programm ohne Betriebssystemunterstützung. Wenn ja, wie würde die Kommunikation/ der Datenaustausch zwischen dem Echtzeitcode und Linux bzw. einer Linuxanwendung grob aussehen?
Student schrieb: > Ist es auch möglich auf einem Prozessor mit Linux ohne > Echtzeiteigenschaften nebenher interruptgesteuert "Echtzeitcode" > auszuführen? In dem Falle wäre das ja quasi ein reines Embedded-Programm > ohne Betriebssystemunterstützung. Das klingt für mich dann eher nach einer Hypervisor-Lösung (Virtualisierung). Also z.B. den Einsatz von XEN oder Jailhouse. Das wäre wohl so die übliche Lösung um neben Linux ein RTOS oder einen BareMetal-Echtzeitprozess laufen zu lassen.
Linux garantiert kein bestimmtes Timing und ist daher raus. Es gibt spezielle Varianten des Linux Kernels für Echtzeit-Anwednungen. Soweit ich weiß, haben die aber viele Einschränkungen und sind halt nicht Standard.
Stefan ⛄ F. schrieb: > Soweit ich weiß, haben die aber viele Einschränkungen So groß sind die gar nicht. Zumindest nicht für PREEMPT_RT. Aber nur durch's patchen allein wird das Gesamtsystem auch noch nicht von automatisch zum Echtzeitsystem. Da gehört schon noch ein bisschen mehr dazu.
Ich hatte vor Jahren mit RTLinux gearbeitet, das als kleiner Echtzeitkern das normale Linux sozusagen als „Idle-Task“ laufen ließ, es erlaubte richtig harte (und auch schnelle) Echtzeit. Deine Forderung ist allerdings um 180° gedreht - ein Echtzeitkern läuft abhängig vom Linux, das könntest Du mit einem Treiber lösen, der im Kernel-Space die Interrupts bedient. Vielleicht kannst Du Dir einen einfachen vorhandenen Treiber auskucken, den Du modifizieren kannst.
moep schrieb: > Das klingt für mich dann eher nach einer Hypervisor-Lösung > (Virtualisierung). > Also z.B. den Einsatz von XEN oder Jailhouse. Danke für die Stichworte. Also scheint auf jeden Fall ein Unterbau notwendig zu sein. Ich dachte, man könnte vielleicht "einfach" eine ISR registrieren, die dann eben vom OS unabhängig operiert. moep schrieb: > Aber nur durch's patchen allein wird das Gesamtsystem auch noch nicht > von automatisch zum Echtzeitsystem. Meinst du die Treiber, z.B. fürs Ethernet, die dann auch echtzeitfähig sein müssen? Gibt es davon abgesehen noch "Baustellen"? Martin H. schrieb: > Deine Forderung ist allerdings um 180° gedreht - ein Echtzeitkern läuft > abhängig vom Linux, das könntest Du mit einem Treiber lösen, der im > Kernel-Space die Interrupts bedient. Ich befürchte aber, dass der Kernel-Space-Treiber auch dem (langsamen) Task-Scheduling unterworfen ist? Oder werden Interrupts direkt bedient? Die Anforderung sollte eigentlich recht normal sein. Man hat einen Echtzeitteil, z.B. für eine Maschinensteuerung, und dann das Linuxsystem für die GUI, wo keinerlei Echtzeit benötigt. Da dachte ich, dass wenn man für den Echtzeitteil keine Linux-Ressourcen benötigt, dass es dann evtl. kein explizites Echtzeitlinux braucht.
Student schrieb: > Also scheint auf jeden Fall ein Unterbau > notwendig zu sein. Ich dachte, man könnte vielleicht "einfach" eine ISR > registrieren, die dann eben vom OS unabhängig operiert. Man kann schon auch eine Lösung ohne Unterbau produzieren. Wie z.B. von Martin oben skizziert. Student schrieb: > Da dachte ich, dass wenn > man für den Echtzeitteil keine Linux-Ressourcen benötigt, dass es dann > evtl. kein explizites Echtzeitlinux braucht. Irgendeine Art von Ressource wird der Echtzeit-Teil ja aber auf jeden Fall benötigen, oder? Für eine Maschinensteuerung sicherlich irgendeine Art von Kommunikation mit der Außenwelt. Student schrieb: > Meinst du die Treiber, z.B. fürs Ethernet, die dann auch echtzeitfähig > sein müssen? Gibt es davon abgesehen noch "Baustellen"? Ethernet-Kommunikation ist per se nicht Echtzeitfähig. Was ich meinte: Es müssen z.B. auch die Taskprioritäten aller beteiligten Teilnehmer betrachtete werden. Also nicht nur die der Applikation sondern auch die der Kerneltreiber die in der Echtzeitkette beteiligt sind. Am Schluss musst du dann schauen, ob du mit deinen Latenzzeiten hinkommst und dann bei Bedarf iterativ prüfen, was dir noch in die Suppe spuckt.
> Linux garantiert kein bestimmtes Timing und ist daher raus. Dein wissen veraltet gerade. .-) https://www.heise.de/newsticker/meldung/Linux-erhaelt-Realtime-Faehigkeiten-vielleicht-schon-im-Winter-4522751.html Allerdings sollte man sich klar machen das Echtzeit auch heissen kann das im Handbuch steht das ein System garantiert in 10s reagieren kann. Olaf
moep schrieb: > Man kann schon auch eine Lösung ohne Unterbau produzieren. Wie z.B. von > Martin oben skizziert. Kennt dazu jemand einen Link oder was wären Stichwörter um danach zu suchen? > Irgendeine Art von Ressource wird der Echtzeit-Teil ja aber auf jeden > Fall benötigen, oder? > Für eine Maschinensteuerung sicherlich irgendeine Art von Kommunikation > mit der Außenwelt. Ja, eben die Datenkommunikation über den RAM, dafür gäbe es aber keine Echtzeitanforderungen, geht ja auch nicht, da der Linux-Task nicht echtzeitfähig wäre. Da ist eben auch die Frage, wie das funktionieren würde. Oder ist man dann eben wieder beim Echtzeitlinux? > Am Schluss musst du dann schauen, ob du mit deinen Latenzzeiten > hinkommst und dann bei Bedarf iterativ prüfen, was dir noch in die Suppe > spuckt. OK, da hilft wohl nur probieren.
Allenfalls waere interessant, was der Poster eigentlich will. Wozu ueberhaupt ein Linux ? Um einen Apache mit einem php in Echtzeit laufen zu lassen ? Etwas in einer Datenbank sortieren lassen ?
Pandur S. schrieb: > Wozu > ueberhaupt ein Linux ? Für's GUI. Steht oben. Student schrieb: > Ja, eben die Datenkommunikation über den RAM, dafür gäbe es aber keine > Echtzeitanforderungen, geht ja auch nicht, da der Linux-Task nicht > echtzeitfähig wäre. Welchen Sinn macht die Verarbeitung der Daten in Echtzeit wenn weder Daten-Eingabe noch Daten-Ausgabe echtzeitfähig sind und mit beliebigem Jitter/Latenz rein-/rausgehen? Erscheint mir wenig Sinnvoll... normal sollte doch die ganze Kette (Eingabe, Verarbeitung, Ausgabe) in Echtzeit laufen. Student schrieb: > Oder ist man dann eben wieder beim Echtzeitlinux? Ein echtzeitfähiger Linux-Kernel mit Echtzeitprozessen für die Datenverarbeitung und Nicht-Echtzeit-Prozessen für die GUI ist hier relativ üblich. Und vermutlich einfacher gemacht als die "Sonderschnitz-Lösung". So lässt sich die ganze Eingabe/Verarbeitung/Ausgabe-Kette in Echtzeit ausführen. Von welchen Echtzeitanforderungen reden wir denn? In welchem Bereich sollen die "Worst-Case"-Latenzen liegen? Welche Hardware ist vorgesehen?
Es geht um einen Prüfstand, Bedienung über die GUI, da kann man vor dem Starten dann auch Daten reinladen. Prozessdaten sollen auch "in Echtzeit" visualisiert werden, aber da das ja eine GUI-Thematik ist, wäre es auch egal, wenn ein Diagramm bspw. eine halbe Sekunde zu spät aktualisiert wird. D.h. es ist keine tatsächliche Echtzeit im Linuxteil notwendig. Prozesswerte sollen auch während dem Betrieb geändert werden können. Aber da gilt ja wieder das gleiche, auf plus/minus eine halbe Sekunde kommt es nicht an. Die Anforderungen an den Echtzeitteil sind mir jetzt selber noch nicht ganz klar. Kommunikation mit einer Treiberplatine vermutlich über SPI im Bereich alle 100µs. Meine Überlegung geht dahin, für den Echtzeitteil den Takt von der Treiberplatine vorgeben zu lassen, und dann mittels Digitaleingang einen Interrupt zu triggern. Aber das hängt auch von den Möglichkeiten von der Linuxintergration ab. Letztlich interessieren mich aber eben auch Standardszenarien. Wenn man sich nur auf das eigene Problem konzentriert, bekommt man ja gern mal einen Tunnelblick. moep schrieb: > Ein echtzeitfähiger Linux-Kernel mit Echtzeitprozessen für die > Datenverarbeitung und Nicht-Echtzeit-Prozessen für die GUI ist hier > relativ üblich. > Und vermutlich einfacher gemacht als die "Sonderschnitz-Lösung". > So lässt sich die ganze Eingabe/Verarbeitung/Ausgabe-Kette in Echtzeit > ausführen. Alles klar, das ist doch ne Ansage :) > Welche Hardware ist vorgesehen? Evtl. BeagleBone Black, aber das ist auch noch offen.
Erfasse erstmal die Anforderungen. Es macht nämlich keinen Sinn, regelrecht explodierende Aufwände hinzunehmen, wenn sich nachher heraus stellt, dass das gar nicht nötig war. In der Regel unterstützt man PC durch Mikrocontroller, die alle Zeitkritische übernehmen. Ganz einfache Beispiele dafür sind: Tastaturcontroller, Mäuse, Drucker, Scanner
moep schrieb: > Ethernet-Kommunikation ist per se nicht Echtzeitfähig. Da ist die Industrie aber völlig anderer Meinung, denn da ist die Migration von allen möglichen proprietären Echzeitprotokollen hin zu Ethernet weitgehend abgeschlossen. Das alte Gerödel hat nur noch Bestandsschutz. Aber klar: es ist nicht ganz das ursprüngliche Ethernet, sondern stärker reglementiert. > Es müssen z.B. auch die Taskprioritäten aller beteiligten Teilnehmer > betrachtete werden. Das war bei echzeitfähigen Kommunikationssystemen schon immer so und wird problembedingt auch immer so bleiben müssen. Ist letztlich exakt dieselbe Soße wie bei der Echtzeitgarantie innerhalb eines einzelnen lokalen Systems.
Moin, Student schrieb: > Evtl. BeagleBone Black, aber das ist auch noch offen. Hat da der SoC drauf nicht noch so exotische Hilfsprozessoren, die exakt fuer so "Realtime" Zeugs gemacht sind? Ich wuerd' niemals so ein Realtime-gepatchtes Linux hernehmen, sondern eher getrennte Prozessoren, einen fuer ein moeglichst unexotisches Allerweltslinux fuer GUI, Ethernet und Gedoens und daneben einen (bare-metal) fuer irgendwelches zeitkritische Zeugs. Wenns zu zeitkritisch wird, dann eher ein FPGA als ein Prozessor. Gruss WK
Student schrieb: > Es geht um einen Prüfstand, Bedienung über die GUI, da kann man vor dem > Starten dann auch Daten reinladen. Prozessdaten sollen auch "in > Echtzeit" visualisiert werden, aber da das ja eine GUI-Thematik ist, > wäre es auch egal, wenn ein Diagramm bspw. eine halbe Sekunde zu spät > aktualisiert wird. D.h. es ist keine tatsächliche Echtzeit im Linuxteil > notwendig. Prozesswerte sollen auch während dem Betrieb geändert werden > können. Aber da gilt ja wieder das gleiche, auf plus/minus eine halbe > Sekunde kommt es nicht an. Viele Hersteller lösen das Problem durch die Integration verschiedener Prozessoren auf einem Chip. Beispiel: Beaglebone AI: Der Sitara 57irgendwas dadrauf hat zwei Cortex A-Kerne für Linux, zwei Cortex M4 und dazu zwei C6000 DSPs für Echtzeit-Sachen. Schau Dir das mal an. Alternative: Zynx 7000'er Serie, dual Cortex A Corex plus FPGA für Echtzeitgeschichten in Logik und ggf einem Microblaze extra. Wird auch gerne genommen. fchk
Stefan ⛄ F. schrieb: > In der Regel unterstützt man PC durch Mikrocontroller, die alle > Zeitkritische übernehmen. Ja, das hab ich mir auch schon überlegt. Ich möchte aber erstmal verschiedene Richtungen andenken. Die Komplexität soll natürlich nicht unnötig groß werden, deswegen frag ich ja auch hier. Dergute W. schrieb: > Hat da der SoC drauf nicht noch so exotische Hilfsprozessoren, die exakt > fuer so "Realtime" Zeugs gemacht sind? Soviel ich weiß schon, hat aber (wenn ich das richtig versteh) nicht die volle Peripherie, sondern ist eher für Spezialanwendungen. > Ich wuerd' niemals so ein Realtime-gepatchtes Linux hernehmen, sondern > eher getrennte Prozessoren, einen fuer ein moeglichst unexotisches > Allerweltslinux fuer GUI, Ethernet und Gedoens und daneben einen > (bare-metal) fuer irgendwelches zeitkritische Zeugs. OK, scheint ja mit Linux an der Seite doch nicht so ohne zu sein. Frank K. schrieb: > Beispiel: Beaglebone AI: Der Sitara 57irgendwas dadrauf hat zwei Cortex > A-Kerne für Linux, zwei Cortex M4 und dazu zwei C6000 DSPs für > Echtzeit-Sachen. Schau Dir das mal an. Mach ich. Wobei ich mir vorstellen kann, dass man dann doch wieder mehr oder weniger an zwei Systemen entwickelt. Aber gut, das ist wohl bei meiner ursprünglich angedachten Lösung auch so. > FPGA Nicht noch ne Baustelle :-)
Moin, Student schrieb: > Soviel ich weiß schon, hat aber (wenn ich das richtig versteh) nicht die > volle Peripherie, sondern ist eher für Spezialanwendungen. Du wirst fuer den zeitkritischen Teil wohl auch nicht die volle Peripherie brauchen. Und Echtzeit ist eine Spezialanwendung. Die Dinger, die ich meine, heissen PRU - Programmable Realtime Unit... Gruss WK
Stepper mit RT_PREEMPT: https://www.youtube.com/watch?v=uIXkvz1-weQ https://www.youtube.com/watch?v=CgtfR5trpO0 Braucht dein Failsafe Echtzeit?
Dergute W. schrieb: > Du wirst fuer den zeitkritischen Teil wohl auch nicht die volle > Peripherie brauchen. Und Echtzeit ist eine Spezialanwendung. Die Dinger, > die ich meine, heissen PRU - Programmable Realtime Unit... Ja, die hab ich gemeint. Im Datenblatt heißt es:
1 | Peripherals Inside the PRU-ICSS: |
2 | – One UART Port With Flow Control Pins, |
3 | Supports up to 12 Mbps |
4 | – One Enhanced Capture (eCAP) Module |
5 | – Two MII Ethernet Ports that Support Ind |
6 | Ethernet, such as EtherCAT |
7 | – One MDIO Port |
SPI und ADC wären schon nicht schlecht.
Student schrieb: > Es geht um einen Prüfstand, Bedienung über die GUI, da kann man vor dem > Starten dann auch Daten reinladen. Prozessdaten sollen auch "in > Echtzeit" visualisiert werden, aber da das ja eine GUI-Thematik ist, > wäre es auch egal, wenn ein Diagramm bspw. eine halbe Sekunde zu spät > aktualisiert wird. D.h. es ist keine tatsächliche Echtzeit im Linuxteil > notwendig. Prozesswerte sollen auch während dem Betrieb geändert werden > können. Aber da gilt ja wieder das gleiche, auf plus/minus eine halbe > Sekunde kommt es nicht an. Das klingt auf den ersten Blick nach einer Anwendung für LabView mit einem CompactRIO System. Aber wie schon gesagt, erstmal Anforderungen definieren. Wenn es um einen Prüfstand (24/7 Betrieb?) geht, würde ich mich nicht damit aufhalten ein System zu basteln sondern einen fertigen Industriestandard verwenden, den man für seine Anwendung konfiguriert.
Stepping into Step schrieb: > Braucht dein Failsafe Echtzeit? Was ist damit gemeint? Es hängen auch Motoren dran, der Steuerungsteil/Echtzeitteil sollte im Betrieb nicht abstürzen. Johannes M. schrieb: > 24/7 Betrieb? Ja. > sondern einen fertigen > Industriestandard verwenden, den man für seine Anwendung konfiguriert. Die Aufgabe ist selbst ein System zu entwerfen. Aber ich wollte hier ja keine konkrete Lösung für mein Problem erfragen, sondern einfach grob verstehen, welche Möglichkeiten es mit Echtzeitlinux gibt. Ich tendier jetzt auch zu einer Aufsplittung auf zwei Controller.
Moin, Student schrieb: > SPI und ADC wären schon nicht schlecht. Ich kenn mich mit dem Ding nicht aus, aber nach bisschen googlen schaut's doch garnicht so schlecht aus: https://git.ti.com/cgit/pru-software-support-package/pru-software-support-package/tree/examples/am335x/PRU_ADC_onChip/README.txt SPI ist so popelig; wenn da ja keine HW das unterstuetzen sollte (Wuerd' mich wundern), dann laesste mit der 2. PRU halt ein paar GPIOs entsprechend wackeln... Bloss mal zur Vorsicht: Das sind keine ganz duennen Bretter, die da gebohrt werden muessen. Also als Abschlussarbeit oder sowas wuerd' ich das bei deinem Wissenstand nicht hernehmen. Dafuer dauert's zu lange und das Risiko, dass was grob schieflaeuft waer' mir zu gross. Gruss WK
Ich mache das nie mit einem Prozessor. Für meinen Echtzeit-Teil nehmen ich einen 2ten kleinen Prozessor. Der kann dann die ganzen Signale sauber regeln, ohne dass ein OS oder eine MMU dazwischen quatscht. Und für den kleinen Echtzeit-Prozessor reicht dann ein Atmel oder Arm-M0. Beides gibts für unter 5 Euro. Minimal und einfach wäre ein Raspi mit einem Arduino verbunden.
Das Problem bei RasPi mit Sekundärprozessor ist die Kommunikation dazwischen. Ideal wäre I2C, aber genau da taugt der RasPi nichts, weil Modul defekt. UART ist deutlich aufwändiger auf Softwareseite.
Oder so was: https://www.heise.de/newsticker/meldung/STM32MP1-ARM-Kombiprozessor-von-STMicroelectronics-4313997.html
oder die STM32H7 die es auch als Dualcore gibt. Die Cortex-M sind nach oben hin auch immer weiter gewachsen, die H7 laufen mit 500 MHz, haben 1 MB Ram und 2 MB Flash. Schon als Singlecore schaffen die richtig was weg und Grafik + sonstige Aufgaben schaffen die recht gut. Dazu ein RTOS um Mess + Steueraufgaben mit hoher Prio zu erledigen.
c-hater schrieb: > Da ist die Industrie aber völlig anderer Meinung, denn da ist die > Migration von allen möglichen proprietären Echzeitprotokollen hin zu > Ethernet weitgehend abgeschlossen. Das alte Gerödel hat nur noch > Bestandsschutz. > > Aber klar: es ist nicht ganz das ursprüngliche Ethernet, sondern stärker > reglementiert. Meine Aussage bezog sich auf Standard-Ethernet in Verbindung mit darauf laufenden Standard-Protokollen wie TCP und UDP, klar. Du sprichst hier von den ganzen Feldbus-Protokollen, die auf Ethernet aufsetzen. Damit ist dann ein Echtzeitverhalten natürlich eher erreichbar. Wenn's um harte Echtzeit mit kurzen Zyklen geht hast du bei Ethernet aber immer das Kollisionsproblem (csma/cd). Harte Echtzeit geht bei PROFINET aber auch erst mit IRT. Und bei EtherCAT z.B. gibt es keinen parallelen Standard-Traffic mehr. Also so einfach ist es im Detail auch nicht ;) Für Ethernet gibt es ja dann bald vllt. mal eine funktionierende Lösung mit TSN :D Student schrieb: > Evtl. BeagleBone Black, aber das ist auch noch offen. Alle 100µs ist da schon sportlich. OSADL nimmt als Faustformel bzgl. der (verhältnismäßig) einfach erreichbaren Latenz für PREEMPT_RT folgendes an: Latenz = (1/CPU_FREQ)*(10^5) Bei einem 1GHz Prozessor wie dem AM335x wären das also 100µs. Natürlich kommt man auch darunter aber da gehen dann die Einzelfall-Optimierungen los. Aus persönlicher Erfahrung (mit dem AM335x und PREEMPT_RT) kann ich dir sagen: Es stimmt so. Man kommt auch deutlich unter die 100µs, aber dann ist es bei weitem keine "out-of-the-box Standardlösung" mehr. Dergute W. schrieb: > Hat da der SoC drauf nicht noch so exotische Hilfsprozessoren, die exakt > fuer so "Realtime" Zeugs gemacht sind? Ich vermute auch, dass du dich bei den Echtzeitanforderungen fast in die Richtung umsehen musst. Beim Beaglebone gibt's die PRUs - wobei die out-of-the-box (wie oben schon steht) kein SPI können. Bei vielen anderen Applikationsprozessoren gibt es ja aber heute auch RT-Subsysteme (bei NXP z.B. oft einen/mehrere Cortex-M on board). Alternativlösung könnte aber tatsächlich die ganz zu Beginn angesprochene Virtualisierung sein. Schau dir mal Jailhouse an (https://github.com/siemens/jailhouse).
moep schrieb: > Alle 100µs ist da schon sportlich. > OSADL nimmt als Faustformel bzgl. der (verhältnismäßig) _einfach_ > erreichbaren Latenz für PREEMPT_RT folgendes an: > Latenz = (1/CPU_FREQ)*(10^5) Wobei man bei einem 100µs-Zyklus ja schon deutlich niedrigere Latenzen bräuchte. Ich denke mittlerweile auch, dass PREEMPT_RT nicht der beste Weg wäre. Dann vielleicht lieber RTAI oder Xenomai, da scheint das Linux ähnlich wie bei einer Virtualisierung parallel und untergeordnet zu laufen. > Aus persönlicher Erfahrung (mit dem AM335x und PREEMPT_RT) kann ich dir > sagen Das ist gut zu wissen, dass du schon mit einem solchen System gearbeitet hast, Erfahrungen aus erster Hand sind immer wertvoll. > Ich vermute auch, dass du dich bei den Echtzeitanforderungen fast in die > Richtung umsehen musst. > [...] > Bei vielen anderen Applikationsprozessoren gibt es ja aber heute auch > RT-Subsysteme (bei NXP z.B. oft einen/mehrere Cortex-M on board). Den i.mx8 habe ich mir schon angeschaut, sieht interessant aus. > Alternativlösung könnte aber tatsächlich die ganz zu Beginn > angesprochene Virtualisierung sein. > Schau dir mal Jailhouse an (https://github.com/siemens/jailhouse). Ich behalt es im Hinterkopf, aber nach kurzer Suche hört sich das erstmal exotisch an. Danke für alle Beiträge!
Student schrieb: >> Bei vielen anderen Applikationsprozessoren gibt es ja aber heute auch >> RT-Subsysteme (bei NXP z.B. oft einen/mehrere Cortex-M on board). > Den i.mx8 habe ich mir schon angeschaut, sieht interessant aus. Cortex-M4 gibts auch schon bei iMX6 z.B. auf diesem Board https://www.udoo.org/udoo-neo/
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.